Showing posts with label Utility. Show all posts
Showing posts with label Utility. Show all posts

Friday, March 14, 2008

Save Ruby objects to disk for later reload

What?

A way to store entire Ruby objects to disk.

Why?

Let's say you have a data structure that takes a long time to build, e.g. dictionary trie for the English language.

It wold be nice to be able to compute this data structure only once, then store it in some way for later retrieval.

How?

Using Ruby's standard library Marshal class, we can easily serialize an object and write it to disk. Combined with the gzip library we even have efficient storage.

Here's the result:


require 'zlib'

# Save any ruby object to disk!
# Objects are stored as gzipped marshal dumps.
#
# Example
#
# # First ruby process
# hash = {1 => "Entry1", 2 => "Entry2"}
# ObjectStash.sotre hash, 'hash.stash'
#
# ...
#
# # Another ruby process - same_hash will be identical to the original hash
# same_hash = ObjectStash.load 'hash.stash'
class ObjectStash

# Store an object as a gzipped file to disk
#
# Example
#
# hash = {1 => "Entry1", 2 => "Entry2"}
# ObjectStore.store hash, 'hash.stash.gz'
# ObjectStore.store hash, 'hash.stash', :gzip => false
def self.store obj, file_name, options={}
marshal_dump = Marshal.dump(obj)
file = File.new(file_name,'w')
file = Zlib::GzipWriter.new(file) unless options[:gzip] == false
file.write marshal_dump
file.close
return obj
end

# Read a marshal dump from file and load it as an object
#
# Example
#
# hash = ObjectStore.get 'hash.dump.gz'
# hash_no_gzip = ObjectStore.get 'hash.dump.gz'
def self.load file_name
begin
file = Zlib::GzipReader.open(file_name)
rescue Zlib::GzipFile::Error
file = File.open(file_name, 'r')
ensure
obj = Marshal.load file.read
file.close
return obj
end
end
end

if $0 == __FILE__
require 'test/unit'
class TestObjectStash < Test::Unit::TestCase
@@tmp = '/tmp/TestObjectStash.stash'
def test_hash_store_load
hash1 = {:test=>'test'}
ObjectStash.store hash1, @@tmp
hash2 = ObjectStash.load @@tmp
assert hash1 == hash2
end
def test_hash_store_load_no_gzip
hash1 = {:test=>'test'}
ObjectStash.store hash1, @@tmp, :gzip => false
hash2 = ObjectStash.load @@tmp
assert hash1 == hash2
end
def test_self_stash
ObjectStash.store ObjectStash, @@tmp
assert ObjectStash == ObjectStash.load(@@tmp)
end
def test_self_stash_no_gzip
ObjectStash.store ObjectStash, @@tmp, :gzip => false
assert ObjectStash == ObjectStash.load(@@tmp)
end
end
end




Here's an example:

# Here's our theory of everything - make it heavy
theory_of_everything = { :question => "Life, Universe & Everything", :answer => 42 }
1000.times {|i| theory_of_everything[i] = "rubbish#{i}" }

# Stash it
ObjectStash.store theory_of_everything, './theory_of_everything.stash'

# Let's see what it did
File.stat('./theory_of_everything.stash').size # => 4206

# Reload it
loaded_theory_of_everything = ObjectStash.load 'theory_of_everything.stash'
question = loaded_theory_of_everything[:question]
answer = loaded_theory_of_everything[:answer]
puts "The answer to #{question} is #{answer}" # => The answer to Life, Universe & Everything is 42


And for the curious - I wrote up a series of tests to make sure I grok how/that this works as I expect it to:


def report msg
puts msg
t=Time.now
yield
puts " -> #{Time.now-t}s"
end

def test_hash_equality hash1, hash2
throw :HashesNotEqual unless hash1 == hash2
throw :HashesNotTreeEqual unless hash1 === hash2
hash1.each do |key,value|
throw :HashCopyDoesNotHaveKey unless hash2.has_key? key
throw :HashCopyDoesNotHaveValue unless hash2.has_value? value
end
end

original_hash = Hash.new
loaded_hash = nil
marshal_dump = nil

report "Build a big hash to be marshalled" do
(0..1000).each do |i|
original_hash[i] = "Entry #{i}"
end
end

report "Store the hash" do
marshal_dump = Marshal.dump(original_hash)
end

report "Load a hash from the dump" do
loaded_hash = Marshal.load(marshal_dump)
end

report "Assert hashes are equal" do
test_hash_equality original_hash, loaded_hash
end

report "Write the marshal dump to file" do
file_out = File.new("marshal_test.tmp",'w')
file_out.write(marshal_dump)
file_out.close
end

report "Construct hash from the marshal file dump" do
file_in = File.new('marshal_test.tmp','r')
loaded_hash = Marshal.load(file_in.read)
file_in.close
end

report "Assert hashes are equal" do
test_hash_equality original_hash, loaded_hash
end

require 'zlib'
report "Gzip the marshaled dump" do
file = File.new('marshal_test.tmp.gz','w')
gz = Zlib::GzipWriter.new(file)
gz.write marshal_dump
gz.close
end

report "Gunzip the marshaled dump and load it" do
gz = Zlib::GzipReader.open('marshal_test.tmp.gz')
loaded_hash = Marshal.load gz.read
gz.close
end

report "Assert hashes are equal" do
test_hash_equality original_hash, loaded_hash
end

puts "Success!"

Tuesday, March 4, 2008

UoC Quickie3 - Now tested for iPhone

I've finally gotten the UoC login bookmarklet (post) to work reliably on the iPhone.

Ge it by saving this UoC Quickie3 link as a bookmark, either by dragging it to your toolbar or right-clicking and saving as a bookmark/favorite.

Two notes of caution: If you enter your information incorrectly the first time you will have to delete your cookies manually to get it to work again. The user name and password is saved scrambled, but in decodable plaintext. As always, protect your cookies.

Sunday, March 2, 2008

UoC Quickie - Rapid Login Bookmarklet

What?

A one click solution to log in to the University of Chicago wireless network - the UoC Quickie3. Drag the link to your bookmark toolbar. Next time you want to log in to the UoC wireless, just click the bookmark. It'll take care of the rest.


Why?
  1. It's annoying to type in your cnet username and password every time you want to check your email.
  2. It's very annoying when on your handheld (iPhone...) to type in your cnet username and password every time you want to check your email
How?

Bookmarks are url's, and url's can contain javascript. This particular javascript
  1. checks that we're on the UoC login page
  2. check if it has stored login information
  3. uses the stored login information to log in, or asks for user name and password
The user name and password are stored as encrypted cookies. However, as always: guard your cookies.

To use the UoC Quickie3, just drag the link to your bookmark toolbar. Next next time you're faced with the UoC wireless login page, just click the bookmark.

Update: If you're an IE7 user, then you will have to right click the link and "add to favorites." If you're an IE6 user... you're out of luck. Microsoft saw to making this impossible. Please download Firefox. IE6 breaks the web.

Update: To get this to work on your iPhone, you have to add it to your Safari bookmarks on your computer and then sync. Unfortunately, there is no other way to get it onto your iPhone.

Update: A missing space in the cookie code messed up the expiration date, resulting in the cookies being trashed when the browser closed. This has now been fixed.

Update: New version! UoC Quickie3 now works on the iPhone. However, make sure you enter your information correctly - the only way to delete it is to manually delete your cookies.

Friday, February 29, 2008

ExtJS & Rails - ExtJS scaffold generator installation script

What?
An automatic installation script for the ExtJS scaffold generator plugin (demo keynotes)to get you up and running.

Why?
Rails' scaffolding gets you up an running lightning fast. ExtJS is a wonderful javascript desktop library. Let's marry them

How?
Run the following script - it will

  • Create the rails application
  • Install the ExtJS scaffolding plugin
  • Download and install ExtJS for your application
  • Generate two sample models - posts and purchases
  • Setup the database
  • Create links to the sample models on the application landing page
  • Run the server
Then all you have to do is point your browser to http://localhost:3000, assuming the server is running on your computer.

Have fun!

# Create the app
rails ext_scaffold_setup
cd ext_scaffold_setup

# Install the plugin and extjs
script/plugin install http://rug-b.rubyforge.org/svn/ext_scaffold
curl -O http://extjs.com/deploy/ext-2.0.2.zip
unzip -q ext-2.0.2.zip
rm ./ext-2.0.2.zip
mv ./ext-2.0.2 ./public/ext

# Generate some scaffolds - posts and purchases
./script/generate ext_scaffold post title:string body:text
./script/generate ext_scaffold purchase order_id:integer amount:decimal description:text

# Create the database for the models
rake db:migrate

# Create links to the models on the landing page
echo '<title>ExtJS Scaffold generator sample</title>echo '<style type="text/css" media="screen">a {text-decoration:none; color:#abc}</style><a href="http://www.blogger.com/posts">Posts</a> <a href="http://www.blogger.com/purchases">Purchases</a>' > ./public/index.html

# All set, run the server!
./script/server

Point your browser to http://localhost:3000, and you're good to go.

Tuesday, February 26, 2008

Hidden OS X Gems

What?

A handpicking of 4 "hidden" OS X gems from OakInnovations' list of 10

  1. Easily compare versions of a file, and cherry pick among the differences: FileMerge

  2. Summarize any text: Summarize

  3. Save snippets of text and images by dragging them from your web browser to the Desktop: Drag n Drop Save

  4. Have folders update their content automatically based on simple rules: Smart Folders
How?
  1. FileMerge - Type in FileMerge in Searchlight, or use the Finder menu Finder > FileMerge > Compare Files

  2. Summarize - Select text, go to the application menu (e.g. Safari) > Services > Summarice

  3. Drag n Drop Save - Just mark the text or picture you want to save, and drag it to the Desktop. (Only works in Carbon applications - yet another reason to switch to WebKit)

  4. Smart Folders - In Finder, File > New Smart Folder (or just hist cmd + opt + N). A smart folder can be really simple and powerful, or complex and very powerful.

    (On my Desktop I have a smart folder Recent Ruby with rules Modified within last 1 day, and name ends in rb. This gives me a quick overview over all the files in all my current Ruby projects that I've worked on today.)

Wednesday, February 20, 2008

Skim - Potential OS X PDF Editor (Open Source)

Looking around for a PDF viewer that lets me annotate the document and doesn't suck, I ran into Skim, an open source PDF viewer and annotator for OS X. It has some obvious shortcomings (such as not being able to edit text), but it's ahead of all other contestants.

I wish it could but it can't...

  • ... edit the document text
  • ... export annotations such that other PDF viewers can see them
However, it...
  • Underlines
  • Highlights
  • Strikes-through
And, like Preview...
  • ... makes red ovals




  • ... creates blaring yellow comment boxes




And, somewhat unnecessarily...
  • ... Green Boxes!









  • ... Icon notes! (Text appears if you double click)








The verdict

Better armored than Preview, but also more cluttered. Clearly the best alternative so far - however, no cigar. It seems to me like someone could make a name for himself cracking this nut. Takers...?

Full screenshot



Review - Open Source PDF Editors

What?


There are plenty of good PDF viewers out there. Combined with the format's platform independence, it makes PDF a great format for presentation.

However, I've never gotten my hands on a good open source PDF editor.

So I took the time to look around a bit. Here's what I found:

  • PDFEdit - free and open source. I couldn't get it to compile on OS X. Here's an article pointing out all its flaws, and still hailing it. That's how bad we need a good open source PDF editor.
  • ReportLab Toolkit - a "mature PDF library." In fact, so mature that it took me 10 minutes of mature fighting with it before I maturely gave up trying to get its demo to work.
  • PDFCreator - Windows only... However, my guess goes against some Microsoft groupie randomly cracking this nut.
  • Skim - The only somewhat promising alternative.
Still no winner. If someone has one, let me know. In the meantime, check out my quick Skim review (it's worth the skim).

Mac OS X : Save PDF's of Any Document with a Click

What?

Save a PDF of any document or picture to pre-determined folders with a quick cmd+p and click (without navigating the directory structure)

How?

  1. Go to /Library (Open Finder, hit Cmd+Shift+G, type /Library, hit Enter)
  2. Find or create a folder named PDF Services
  3. Open a new Finder window, and create the Folders you want to save PDF's to (hit Cmd+N, and hit Cmd+Shift+N to create each Folder)
  4. Create an alias for each Folder (Select all folders, hit Cmd+L)
  5. Drag all aliases to the /Library/PDF Services folder in the first window
Done. You will now have the selected folders appear in the save menu.

Extra Hint

You can alias other things than Folders. If you often read and highlight created PDF's in, say, Acrobat Reader, then try to alias the Acrobat Reader application and put it in /Library/PDF Services as well.

Thank you

Macworld for the great article, with this and other tips.