Thoughtlets, Music, and Code from Noah Thorp

My Rubyconf 2009 Audio Talk Posted on Confreaks

Posted: February 18th, by Noah

My talk at Rubyconf 2009 on using Ruby for audio projects was posted. I focus on frequently unfamiliar open source libs that people may find useful and make reference to a number of BArCMuT presenter’s projects. There’s a lot of talk about using Ruby and Chuck, SuperCollider, solving sync issues, etc, etc. You can find the source code for the presentations on github here

One major Ruby discovery since then is that Charles Nutter (a primary author of jRuby) has a version of Ruby that uses static typing, runs on the JVM, and runs at the speed of Java! It’s called duby and it’s available here

jQuery Wherefore Doth Thy Includes Go?

Posted: July 20th, by Noah

Whither Javascript

Recently I have been working on a Rails project with lots of Javascript include complexity ( Ashbury Music Hall ). Here’s the challenge:

  • Some larger libraries and plugins only need to appear on single pages (e.g. Thickbox, FCKEditor).
  • Some Ajax page renders depend on core libraries (e.g. jQuery) but shouldn’t be loaded more than once by layouts and partials
  • When Ajax page renders degrade to linked pages they may be in alternate layouts and include different Javascript libraries or have different load orders
  • Rails partials load before layouts and potentially include Javascript files specified in them before core libraries
  • Page and partial specific Javascript (e.g. myview/my_page.js ) presents even more complexity
  • Pages appear to load faster if Javascript is loaded on the bottom of the page

Oh what a tangled web we weave.

Thither

The solution I arrived at is to specify sectional order of libraries, accumulate them, deduplicate them, and include them at the end of the page request. This allows definition of core libraries at the top of a layout page for all partials and inclusion of librararies in plugins on any view or partial without duplicate loading or core library omissions. To do this I defined two Application Helpers as follows:

# Use accumulate_js to accumulate javascript paths throughout the application
# it deduplicates them and then they should be included by calling include_accumulated_js
# at the foot of the page.
def accumulate_js(key, path)
  @javascript_list ||= {} 
  @javascript_list[key] ||= []      

  if path.class == Array || path.class == String
    @javascript_list[key].<<(path)
    @javascript_list[key].flatten! # for some reason + was not working properly for arrays
    @javascript_list[key].uniq!
  else 
    raise ArgumentError
  end
  @javascript_list
end

# call accumulate_js first to use the default @javscript_list instance var
def include_accumulated_js(order_array, path_hash = @javascript_list)
  result = "" 

  order_array.each do |key|
    next unless path_hash[key]
    result += path_hash[key].inject("") do |result, path|
      result += javascript_include_tag(path)
    end
  end
  result
end

Then wherever Javascript is called for a request (layout, view, or partial) the names of the libraries are accumulated:

accumulate_js(:core, ["jquery-1.3.2.min.js", "jquery-ui-1.7.1.custom.min.js"])
accumulate_js(:plugins, "beautytips/jquery.bt.min.js")
accumulate_js(:application, "application")

All load path strings from the public/javascripts directories are specified. The library order is maintained but additional loads are de-duplicated. Then all of the libraries are loaded at the foot of the document, ordered by type with a command like this:

include_accumulated_js([:core,:plugins,:application,:page,:partial])

For the specifics of what it does, here’s the rspec spec:

describe "javascript library acuumulation" do
  it "accumulates javascripts associated with a specific key" do
    accumulate_js(:core,["a","b"])
    accumulate_js(:core,"c").should == {:core => ["a","b","c"]}
  end

  it "can accumulate a list of javascripts used on a web page" do
    accumulate_js(:core, "library.js")
    accumulate_js(:core, "another/library.js").should == {:core => ["library.js", "another/library.js"]}
  end

  it "can take combinations of arrays and strings" do
    accumulate_js(:foo, ["lib1.js","lib2.js"])
    accumulate_js(:foo, "lib3.js")
    accumulate_js(:foo, ["lib4.js","lib5.js"]).should == {:foo => ["lib1.js","lib2.js","lib3.js","lib4.js","lib5.js"]}
  end

  it "raises an error if it is of an unknown type" do
    lambda do
     accumulate_js(:foo, 1)
    end.should raise_error(ArgumentError)
  end

  it "deduplicates and preserves order" do
    accumulate_js(:baz, ["a","b","a","c","b","c"]).should == {:baz, ["a","b","c"]}
  end
end

describe "including accumulated javascript" do
  before(:each) do
    accumulate_js(:foo, ["foo_1","foo_2"])
    accumulated = accumulate_js(:baz, ["baz_1","baz_2"])
    @result = include_accumulated_js([:baz, :foo], accumulated)
  end

  it "returns javascript includes" do
    @result.should =~ /script.*src.*javascripts\/baz_1.js.*type.*text\/javascript/ 
  end

  it "includes javascripts in the specified order" do
    @result.should =~ /baz_1.*baz_2.*foo_1.*foo_2/m
  end
  it "can handle nil values" do
    accumulated = accumulate_js(:foo, ["foo_1","foo_2"])
    lambda do
      include_accumulated_js([:baz, :not_in_there], accumulated)
    end.should_not raise_error
  end
end

Accolades

Marc Grabanski, excellent jQuery developer that he is, contributed his sage advice to this solution.

Epilogue

I might put this in a plugin and post to github, but just seems a little silly since there are only two helper methods. What think ye? If this blog post is good enough for you, then it’s good enough for me. Obviously, I’m busy enough that I’ve gone bonky and resorted to archaic english – but if you request a plugin or some other container I may be obliged.

Ruby Value To Boolean Method

Posted: June 25th, by Noah

It’s a common problem that does not seem to have a standard solution. Sometimes you need to coerce a value to a boolean (e.g. from a web form). Here’s a simple implementation I wrote that handles common strings and numbers and gives flexibility in how to treat nils.

Here’s the behavior we want:
  describe "#to_boolean" do                                                                         
    it "converts false values" do                                                                   
      ["no","false",false, "0", 0].each do |value|                                                  
        to_boolean(value).should == false                                                           
      end                                                                                           
    end                                                                                             

    it "converts true values" do                                                                    
      ["yes","true",true, "1", 1].each do |value|                                                   
        to_boolean(value).should == true                                                            
      end                                                                                           
    end                                                                                             

    it "is case insensitive for strings" do                                                         
      to_boolean("YeS").should == true                                                              
      to_boolean("NO").should == false                                                              
      to_boolean("TruE").should == true                                                             
      to_boolean("FalSe").should == false                                                           
    end                                                                                             

    it "converts nil to false by default" do                                                        
      to_boolean(nil).should == false                                                               
    end                                                                                             

    it "can return nil as nil" do                                                                   
      to_boolean(nil, nil).should == nil                                                            
    end                                                                                             

    it "converts unmatched strings to true" do                                                      
      to_boolean("a string").should == true                                                         
    end                                                                                             
  end

Here’s the source code that satisfies the desired behavior:

def to_boolean(value, nil_value = false)
  value.downcase! if value.class == String
  case value
  when "no","false",false, "0", 0
    false
  when "yes","true",true, "1", 1
    true
  when nil
    nil_value 
  else
    !!value
  end
end