Boogaloo Simple Cache Server 0.1

Hey all,

I’ve just made the first release of a new project: Boogaloo.

Boogaloo is a very simple cache server that provides persistent and
temporary caches. You can also use it to house your own custom services.
It’s meant to be very simple to use so that you can concentrate on your
primary problem.

You’ll find it fully documented and even has a few unit tests:
http://boogaloo.rubyforge.org/
or “sudo gem install boogaloo” if you want to play straight away.

Why?

It started out as a place to cache my rendered Liquid template objects
and
somewhere to store a list of selectors from some CSS files. Later on I
started using it as a temporary cache for objects that were only
relevant to
specific user in Rails. So instead of keeping the object in the users
session and forgetting to clear it out later, I can now just stick it in
Boogaloo and let it expire after a period given. This is very handy for
multi-step forms etc.

Anyway, I hope someone finds it useful…

Cheers,
Ian.

On 10/14/06, Ian L. [email protected] wrote:

http://boogaloo.rubyforge.org/
multi-step forms etc.

Anyway, I hope someone finds it useful…

Cheers,
Ian.

Interesting, so where do you cache the data that clients send you?

Currently they’re only cached in memory, I could add pickle the cache to
disk on server shutdown if there is demand for it.

Hi, I’m currently working on a side project which has me store binary
content in memory.
In order to make it’s use as transparent as possible, i overloaded the
‘require’ method to search as well in the memory and this works fine at
the moment. In the same line of thought, I tried changing the way
File.new works to return a StringIO object pointing to my binary data in
memory instead of an ordinary IO object… However, i ran into an
interesting problem. Consider the following code:

class File
alias_method :old_new, :initialize

def initialize(*args)
    if args[0] == 'a.txt'
        # Do not return a file object, return say, a Hash
        Hash.new
    else
        old_new(*args)
    end
end

end

o = File.new(‘a.txt’)
puts “Object is of class: #{o.class}”

This outputs:
Object is of class: File

Obviously. Now, looking further for alternatives, i tried to overload
Class.new. Consider the following code:
class Foo
end

class Bar
end

class Class
alias oldNew new
def new(*args)
print "Creating a new ", self.name, “\n”
if self.name == ‘File’
require ‘stringio’
StringIO.new(‘This is a string!’,‘r’)
elsif self.name == ‘Foo’
Bar.new
else
oldNew(*args)
end
end
end

d = Foo.new
puts “Should be type Foo and is: #{d.class}”
n = File.new(‘lol.rb’,‘r’)
puts “Should be type StringIO and is: #{n.class}”
puts “Content is: #{n.read}”

With a file named lol.rb in my path with the single line of content:
“Hello”, this outputted:
Creating a new Foo
Creating a new Bar
Should be type Foo and is: Bar
Should be type StringIO and is: File
Content is: Hello

==========================
Two things here:
Class.new is working as expected with Foo, returning a Bar object. But,
when File.new is called, Class.new is not called as it was for Foo.new!

Any thoughts/help please? I have ran out of ideas… An obvious solution
is to use a different constructor that is not File.new but that would
make it not very elegant.

Thanks and regards.
Nicholas

On Sun, 15 Oct 2006, Nicholas Frechette wrote:

Hi, I’m currently working on a side project which has me store binary
content in memory. In order to make it’s use as transparent as possible, i
overloaded the ‘require’ method to search as well in the memory and this
works fine at the moment. In the same line of thought, I tried changing the
way File.new works to return a StringIO object pointing to my binary data in
memory instead of an ordinary IO object… However, i ran into an
interesting problem. Consider the following code:

the way to accomplish this is to use mmap. that’s what the call
basically
does: map file to memory and return them as strings. if you create more
than
one mapping you will not map the file twice (if you give the right flags
to
the ctor). here’s a little example of using mmap to modify the running
program:

here’s the program

 harp:~ > cat a.rb
 require 'mmap'

 mmap = Mmap.new __FILE__, 'rw', Mmap::MAP_SHARED

 mmap << { mmap => Time.now.to_f.to_s }.inspect << "\n"
 mmap.msync
 mmap.munmap

 p DATA.readlines

 __END__

here’s one run

 harp:~ > ruby a.rb
 ["{#<Mmap:0xb75cc79c>=>\"1160922660.6115\"}\n"]

 harp:~ > cat a.rb
 require 'mmap'

 mmap = Mmap.new __FILE__, 'rw', Mmap::MAP_SHARED

 mmap << { mmap => Time.now.to_f.to_s }.inspect << "\n"
 mmap.msync
 mmap.munmap

 p DATA.readlines

 __END__
 {#<Mmap:0xb75cc79c>=>"1160922660.6115"}

here’s the next

 harp:~ > ruby a.rb
 ["{#<Mmap:0xb75cc79c>=>\"1160922660.6115\"}\n", 

“{#Mmap:0xb75d079c=>“1160922666.11629”}\n”]

 harp:~ > cat a.rb
 require 'mmap'

 mmap = Mmap.new __FILE__, 'rw', Mmap::MAP_SHARED

 mmap << { mmap => Time.now.to_f.to_s }.inspect << "\n"
 mmap.msync
 mmap.munmap

 p DATA.readlines

 __END__
 {#<Mmap:0xb75cc79c>=>"1160922660.6115"}
 {#<Mmap:0xb75d079c>=>"1160922666.11629"}

as many times as you might call " Mmap.new FILE, ‘rw’,
Mmap::MAP_SHARED "
your process will only have one mapping. in fact, you really cannot map
it
more times:

 harp:~ > cat a.rb
 require 'mmap'

 mmaps = Array.new(3){ Mmap.new __FILE__, 'rw', Mmap::MAP_SHARED }

 mmaps.each do |mmap|
   mmap << { mmap => Time.now.to_f.to_s }.inspect << "\n"
   mmap.msync
   mmap.munmap
 end

 p DATA.readlines

 __END__


 harp:~ > ruby a.rb
 ["{#<Mmap:0xb75d179c>=>\"1160922968.42437\"}\n"]


 harp:~ > cat a.rb
 require 'mmap'

 mmaps = Array.new(3){ Mmap.new __FILE__, 'rw', Mmap::MAP_SHARED }

 mmaps.each do |mmap|
   mmap << { mmap => Time.now.to_f.to_s }.inspect << "\n"
   mmap.msync
   mmap.munmap
 end

 p DATA.readlines

 __END__
 {#<Mmap:0xb75d179c>=>"1160922968.42437"}

notice how the second and third calls were no-ops. that’s because all
three
mappings were actually the same, and unmapping the first unmapped the
rest -
leaving the rest of the loops as no-ops.

regards.

-a

On 10/15/06, Nicholas Frechette
[email protected] wrote:

        old_new(*args)

Any thoughts/help please? I have ran out of ideas… An obvious solution
is to use a different constructor that is not File.new but that would
make it not very elegant.

SomeClass#initialize is not SomeClass::new, only the return value of
new decides what the returned object is.
As for overriding Class::new, that’s just not necessary and there
probably is a File::new or IO::new that prevents Class::new from being
called.

Try
class File
alias …
def self.new(*args)
if …
return {}
else
old_new(*args)
end
end

Please don’t hijack threads, it makes a mess of things. Thanks.

David V.