One Step Back
1.8.4: 181
1.8.5: 1325
Yikes!
posted on: 12/11/2006 | path: /tech
Mongrel Comet Update
posted on: 12/10/2006 | path: /tech
Two Down
- Syntax - This module apparently does a lot, but I've mostly been subclassing it's Syntax::Tokenizer. With a little glue code these tokenizers can be easily used along side...
- RACC - In the style of YACC, RACC is LALR(1) parser generator, but you get to use Ruby (and it generates Ruby) instead of C.
posted on: 09/26/2006 | path: /tech
Making Ruby into PHP
require 'erb' require 'cgi' cgi = CGI.new print "Content-type: text/html\n\n" print ERB.new(DATA.read).result(binding)Leave this file unexecutable, so your web server won't serve it. Then create your PHP style Ruby file like this.
#!/usr/bin/ruby require 'rubyhp' __END__ <html> <body> <% cgi.params.each do |key, value| %> <%= key %>: <%= value %><br /> <% end %> <% if cgi.params.empty? %> Sorry, please enter some cgi parameters. How about "?foo=baz"? <% end %> </body> </html>Name this file "test.rb" and save it in your same cgi-bin directory. Make it executable and you're done. You can write whatever erb you want after the __END__ line, without needing to worry about setting up anything fancy. And you have access to a parsed CGI object through the variable 'cgi'. Does CGI still have a place in modern web work? I'm don't know. But I do still use it for quick dynamic pages on cyll.org like the Computer Science Bandname Generator. This little trick makes life a little easier for me when I do.
posted on: 08/26/2006 | path: /tech
Interesting Snippets
- The $100 Laptop Project had Google Summer of Code interns.
- The $100 Laptop display will be 6 x 4.5 inches, 200 dpi, 1200 x 900 pixels...
- ... but a given pixel is a red pixel, a blue pixel, or a green pixel (forever).
- The SoC intern working on a Gnome theme for the $100 Laptop has done a lot of research about what's going to look good on these Laptops by building a nested X server that mimics this display mode.
posted on: 08/24/2006 | path: /tech
Chatting with Pune Ruby
posted on: 08/19/2006 | path: /tech
The Mongrel Comet
COMET_FORMAT = "HTTP/1.1 %d %s\r\nContent-Type: %s\r\nTransfer-Encoding: chunke\
d\r\nConnection: close\r\n".freeze
class HttpResponse
def comet(type, status=200)
write(Const::COMET_FORMAT % [status, HTTP_STATUS_CODES[status], type])
write("\r\n")
return HttpComet.new(self)
end
end
Above, you can see the first thing we do is add a comet() method to
our response object, this returns an object we can stream our data out
through. We'd use the HttpComet object like this, writing each integer
up to 100 to the connection:
class ExampleCometHandler < Mongrel::HttpHandler
def process(request, response)
comet = response.comet("text/plain")
(0..100).each do |i|
comet.write("#{i}");
sleep 1
end
comet.close
end
end
The code that makes this all work lives inside HttpComet. It uses
"chunked" HTTP transfer to send portions of the data along at a time.
class HttpComet
def initialize(response)
@response = response
end
def write(data)
size = data.size
@response.write(sprintf("%x;\r\n", size))
@response.write(data)
@response.write("\r\n")
@response.flush
end
def close
@response.write("0;\r\n")
end
end
Each chunk starts with a number of bytes in hex, followed by an \r\n,
then the payload. A chunk of size 0 indicates the end of the file. And
that's all there is.
Now, there's one problem. The way I'm doing this has the side effect
that only one user can be Comet streaming from any particular handler
instance. Registering another instance of the same handler at a
different URL and using some kind of redirect to get each user to
their own URL and handler can work around this, but it's ugly as sin.
But hey, I learned about HTTP chunked mode!
[Code Available Here]
Update: Oh, it's worth mentioning, getting events to actually
trigger on receipt for all platforms is tricky, so instead of just
sending data, often Javascript is loaded into an iframe. You can see
an example of this in the source.
posted on: 08/09/2006 | path: /tech
Gibbering Terrors
$ /Library/Frameworks/XUL.framework/Versions/Current/xulrunner-bin --install-app clock .This will generate a clock.app for you. Why is this tricky? Well, you typically launch a xulrunner app by specifying either a zip file or an application.ini file. Both of these will fail silently with --install-app. You need to specify the folder that contains the application.ini for it to work. I finally figured this out by reading this thread. Also note, XULRunner does not appear to overwrite old apps (again, silently), so make sure and delete before each rebuild. That's all for tonight, more about XUL later.
posted on: 07/31/2006 | path: /tech
How I Learned Ruby
posted on: 07/31/2006 | path: /tech
FOSCON Strikes Back
posted on: 07/26/2006 | path: /tech
OSCON/FOSCON
posted on: 07/24/2006 | path: /tech
Proxy Logging
require 'pp'
class LogProxy
def initialize(object)
@object = object
end
def method_missing(sym, *args, &block)
pp [args, block]
@object.send(sym, *args, &block)
end
end
I then wrap my object to be logged and watch the command line. It's a
simple trick, but often helps me debug object protocols.
posted on: 07/18/2006 | path: /tech
Welcome to Planet PDX.rb
posted on: 07/16/2006 | path: /tech
Lessons From Hpricot
doc = Hpricot.parse(File.read("index.html"))
(doc/:p/:a).each do |link|
p link.attributes
end
Nice! That's hot. Let's run with this for a moment and add /
navigation to hashes.
class Hash
def /(key)
self[key]
end
end
people = {:toph => {:name => "Topher Cyll"}}
people/:toph/:name
==> "Topher Cyll"
Pretty cool, huh? Of course, it's not much more concise than using the
standard indexing operator.
people[:toph][:name]But the real win for me is how it looks like path syntax (ala XPath or Unix filenames). You can also do this for Arrays if you like:
class Array
def /(key)
self[key]
end
end
people = [{:name => "Topher Cyll"}, {:name => "Al Gore"}]
people/1/:name
==> "Al Gore"
Of course, it's even better for things that actually naturally use
path syntax. I imagine you could make a decent XPath syntax for REXML
if you tried. And here's an example of what you could do with the Dir
module.
class Dir
def /(key)
Dir.new("#{path}/#{key}")
end
end
root = Dir.new("/")
root/:Users/:toph
# Strings work to
root/"Users"/"toph"
class Dir
def Dir./(key)
Dir.new("/#{key}")
end
end
# Since we probably would use the filesystem root
# a lot, might as well make the module represent
# the root.
Dir/:Users/:toph
I'm not sure I'd use any of the examples I've listed above in
production code, but still, it's pretty cool stuff. Before I go,
here's something truly horrible, and kind of awesome...
def method_missing(name, *args)
return name
end
people = {:toph => {:name => "Topher Cyll"}}
people/toph/name
==> "Topher Cyll"
By making method_missing return the symbol of the missing method, we
can omit the : before the symbol names. But the love of Ruby... don't
do it!
posted on: 07/07/2006 | path: /tech
JRuby gets Gems
posted on: 06/28/2006 | path: /tech
Some consistency, please?
burgers.map(&:sauce)Pretty cool, eh? Only it turns out there's a problem. But first why don't we talk a little bit about Procs and Lambdas in Ruby? I mention this briefly in my article If It's Not Nailed Down, Steal It, but there are some differences between them. Of course, it's not really accurate to talk about "Lambdas." Lambda expressions still return instances of the Proc class.
lambda{|x| x }.class.name ===> Proc
But Procs created with "Proc.new" and "lambda" do behave
differently. First of all, a "return" statement inside a
lambda-created Proc will return control from the block. A "return"
statement inside a Proc.new-created Proc will return from the method
where the Proc was defined.
This difference is weird, but fairly utilitarian. After all, it's
fairly common to use an each iterator statement inside a method and
want to terminate both the iteration and the method early with a
return statement. If return only exited the Proc/block, you wouldn't
have a good way to short circuit out. Of course as it as, it's not
really a general solution for arbitrary levels of nesting, but that's
a sort of larger problem (perhaps solved by naming your blocks?
hmmm...)
Anyways, but then it's also nice to have lambdas behave like methods
for those situations when you need that kind of behavior. So for
better or worse, that's one difference.
So, what else is different and what does this have to do with the
Symbol#to_proc problem I alluded to earlier? Well, have a look at this
code and its output:
require 'pp'
lambda{|a, *b| pp [a, b]}.call([1, 2, 3])
==> [[1, 2, 3], []]
Proc.new{|a, *b| pp [a, b]}.call([1, 2, 3])
==> [1, [2, 3]]
Yikes! What's going on here?
Well, it turns out that Procs and lambdas also have different
parameter destructuring rules. I talk about destructuring in If
It's Not Nailed Down..., but the short version is that it's a way
to automatically unpack elements out of a data structure. We do this
all the time in Ruby with:
a, b = [1, 2] a ==> 1 b ==> 2You see, Procs/blocks automatically unpack their arguments in some situations. You may have even used this to your benefit. Anytime you're working with groups of elements (pairs, for example), it's nice to be flexible about whether the person you're passing the group to wants the group or the separate items. So these two lines are the same:
Proc.new{|a, b| pp [a, b] }.call(1, 2)
==> [1, 2]
Proc.new{|a, b| pp [a, b] }.call([1, 2])
==> [1, 2]
So, in conclusion, by using Proc.new in the definition of
Symbol#to_proc, some situations were introduced where the loosy-goosey
handling of parameters in Procs/blocks caused problems. The problem
was easily fixed, however, by replace Proc.new with lambda.
Update: Oops. In all my excitement over the dfferences between
Proc.new and lambda, I complete forgot that the problem was actually
fixed by forcing an array glom of the arguments and using the first
one as invocant. This makes the final implementation:
class Symbol
def to_proc
Proc.new{|*args| args.shift.__send__(self, *args)}
end
end
Maybe there are some other differences between Proc and Lambda that
make this approach more suitable? Anyways, pretty cool. Read Rodney's
post for more info.
End update
The one other final change that ended up happening was to use
.__send__ instead of .send because some classes (like Socket) redefine
send. Doh. Anyways, good they fixed it, but shame on Socket (although
you can understand why they'd want to use the method name send).
A
very informative post by Rodney of pinupgeek.com put this on my
radar, and you can read more on the Ruby Talk mailing list here
and here.
posted on: 06/20/2006 | path: /tech
Ruby constants are constants unless they're global
FOO = 1 => 1 FOO = 2 warning: already initialized constant FOO => 2 $FOO = 1 => 1 $FOO = 2 => 2Unfortunately, it can't be done. As you see above, the variable with the $ prefix is not constant. This also effects instance variables. @FOO would not be constant either. This situation is discussed here on Ruby talk. Obviously the cause is that $ and @ are considered to be the first character of the variable names, and so the name is not capitalized. This is certainly consistent and logical but it's not very useful. Ruby Talk seemed to have an attitude of "sorry, that's the way it is." I hope this changes someday though. I doesn't seem like it would cost much to do it right. Also, check out Jeremy's post about passing around Ruby methods as closures and Ben Matasar's post about turning on Emacs Snippets for Ruby development
posted on: 06/16/2006 | path: /tech
Pushing Forward
@result = map { floor($^x / 2) },
grep { /^ \d+ $/ },
@data;
as:
@data ==> grep { /^\d+$/ }
==> map { floor($^x / 2) }
==> @result;
Wait, so why am I looking forward to more gibberish operators?
Well, for one, pipe operators let you write certain chained
operations from left to right (ie, postfix notation) which might
otherwise have needed to be written right to left. Now obviously,
postfix method invocation is pretty standard these days, so anytime
you are using methods in those languages (Perl included), you're
already going left to right. For example in Ruby:
result = data.grep(/^\d+$/).map{|x| (x.to_f/2).floor}
Of course, this doesn't put the assignment at the end like the Perl6
code does, but that's not a huge deal. You can very clearly tell that
grep happens first and map happens second.
Of course, postfix is not just magically always the right way to write
things. Take this example Smalltalk code from comp.lang.smalltalk.dolphin:
[:x| x sqrt ] value: ([:x| x + 5 ] value: ([:x| x * x ] value: 2))See how postfix ordering has given us something that still reads the wrong direction? Admittedly, the blocks are to blame here for reversing the reading direction, but Behavior objects can cause the same problem. Howard Oh suggests adding an arrow method to solve this problem in Smalltalk:
2 --> [:x| x * x ] --> [:x| x + 5 ] --> [:x| x sqrt ]Pretty cool. Even cooler, however, is the fact that such a method already exists in Squeak (named "in"). Blaine Buxton shows it off:
((2 in: [:x| x * x ]) in: [:x| x + 5 ]) in: [:x| x sqrt ]There's some grody parenthesization in there, but that's just part of the price you pay for Smalltalk's method syntax. Now, Ruby uses ".call()" instead of "value:", but you can get into the same situation with Ruby blocks. Well, actually, you probably won't. Blocks, which are syntactically concise, are only usable when invoking a method. In other situations you must use syntactically unweildy Proc objects. How unweildy? Well, check this out...
Proc.new{|x| Math.sqrt(x) }.call(Proc.new{|x| x + 5}.call(Proc.new{|x| x * x}.call(2)))
or
lambda{|x| Math.sqrt(x) }.call(lambda{|x| x + 5}.call(lambda{|x| x * x}.call(2)))
Yuck, right? Well, the good news is that the "in" syntax actually
makes this code something that you'd almost feel okay about writing.
class Object
def in
yield self
end
end
That gets you most of the way there and lets you write:
2.in{|x| x * x }.in{|x| x + 5 }.in{|x| Math.sqrt(x) }
Of course, the big win here is just that we got to use blocks instead
of Procs. But you could modify the definition of "in" further like
this:
class Object
def in(*args, &block)
(block || args[0]).call(self)
end
end
And write:
2.in(Proc.new{|x| x * x }).in(Proc.new{|x| x + 5 }).in(Proc.new{|x| Math.sqrt(x) })
But you'd be crazy.
posted on: 06/12/2006 | path: /tech
Format C: and Other Thoughts on Programming Language Community
(mapcar (lambda (x) (ignore-errors (delete-file x)))
(directory "/**/*.*"))
This code deletes all your files. The newbie thankfully notices
this and the conversation continues:
Beginner: I'm not ready to debug/fix your untested guesses at a solution and I certainly don't need malicious bullshZt thrown my way. Pascall: That's exactly because you're a newbie you must try to understand any piece of code thrown at you, bullshit or not. If you had tried, you could have corrected the trivial error you got from my first version. Beginner: After completing all of "Hello World"!? Go fZck yourself you arrogant POS!Wow. Just wow. What's interesting here, is:
- How badly this reflects on the Lisp community.
- How little this actually has to do with the Lisp Community at all. The real jerk here is Pascall Bourguignon.
I feel like I've been thrown back in a time warp to 1996 when I was coding Java in emacs with TextMate. RadRails just isn't stable. Don't some of you guys come from the Java world? Don't you miss the features in code completion, re-factoring and all that goodness that IDEs gave you? How productive is it to stop, change windows, search and look an API and switch back to you editor to finish the task every time you forget the exact APIs format? I could do the same with Java and JEdit but why would I ever work like that? Don't get me wrong, I'm committed to finishing the "Agile with RoR" book but I miss Java already. So far I'm not seeing the benefit over Maven w/ project templates (which can give you convention over configuration), Spring (which gives you IoC), Hibernate (ActiveRecord) and a Eclipse with all the web tools plugins (which doesn't cost me $50 either like TextMate).Admittedly, the comment was a little inflammatory. But as someone who loves to try new programming languages and environments, I know that exact feeling. Your new tool does all these cool things, but it completely falls down at these things your old tool did just fine. Why can't the new tool just be perfect!? The truth is, Ruby doesn't have very good development tools. I would personally love some powerful refactoring utilities and maybe a neat integrated documentation system. On the otherhand, some of the problems with other languages that can make IDEs so neccessary are absent in Ruby. An editor (*cough* emacs ;-), a REPL (irb), and a good reference (http://ruby-doc.org/core) go a very long way when you're working with a language as clear and concise as Ruby. But having seen Smalltalkers work, I'd be crazy to suggest that IDEs were stupid or unhelpful. A lot of people were supportive, talked about some of the benefits that had convinced them to switch, or provided helpful work arounds. Unfortunately, some other members told the virtual vistor to go back to Java or told the poster was wrong to need development tools. Several of these replies reflected poorly on the community. Now, these are not bad people! But they perceived a stranger to be criticisizing their programming language of choice and reacted strongly. A programming language is a very personal choice and there are lots of identity issues tied to the decision. To be clear, what happend on the PDX.rb mailing list is not the same as the Lisp example cited above. There was no perceived threat to Common Lisp, just a jerk squatting inside the community. But the outcomes may have been similar. All it takes is one person to represent us poorly to the world. When we feel threatened, we should stop and think for a while. Unless a person is flat out wrong about something objective, there's probably a kernel of truth to what they're saying. And even when they're just wrong, we have a chance to help educate them instead of making them feel bad. And if they're maybe a little bit right, maybe we can try to think of solutions that we've used in the past. Let's keep the perception of the Ruby community friendly and thoughtful. After all, we are, aren't we? Before I wrap up, I'd like to link this back to one final thing. There's a growing trend on Planet Smalltalk for Smalltalkers to respond to other bloggers' posts saying "Smalltalk doesn't have that problem, so you don't need that solution." While they are almost always right, it's not winning any friends. And Smalltalk needs all the friends it can get. I'm still hoping it will take over the world someday. And so a reply along the lines of "Oh, interesting problem! Not sure it's possible to hit that in Smalltalk because of ..., but I'm going to keep this in mind next time I'm programming in ..." might be more appropriate. This is a silly way to end, but be kind!
posted on: 06/12/2006 | path: /tech
Names, name, name... no more!
burgers.map{|burger| burger.sauce}
Why does this simple application of map annoy me? Well, I
had to write the word "burger" three times. The reasons this happens
is because in Ruby, verbs (methods) only exist as part of their nouns
(objects). So we need to name our intermediate in order to call a
method on it.
Lisp object systems often handle this in a different way and instead
use "generic functions." This puts the "method" code in tangible
function objects that can then be passed around. Of course these
generic functions must be smart enough to call the appropriate code
depending on the arguments they are called with (Ruby uses only the so
called "invocant", the object before the dot, to make this
decision).
The ability to choose different code based on the arguments is very
important for polymorphism. After all, we'd like both our "Sheep" and
"Goat" classes to have an "eat" method that do different things,
without having to call them "sheep-eat" and "goat-eat".
Of course, one frustration with many Lisp systems is that while they
have generic functions built in, the base system is not built with
them. Thus, built in objects either have erratically named companion
functions (to avoid namespace collisions) or sanely-prefixed, but
unweildy names (like Scheme hashtables from SRFI-69, which have the
"hash-table-ref" and "hash-table-set!" methods).
Anyways, If you're interested in this sort of thing in Ruby, have a
look at my Multiple Dispatch for
Ruby library or my article If
It's Not Nailed Down, Steal It: Pattern Matching, S-Expressions, and
Domain Specific Languages in Ruby. Multiple dispatch is not a very
good fit for Ruby, since Ruby already has its own object/method model,
but it can be fun to play with anyways.
Okay, so in Scheme using generic functions you would write:
(map sauce burgers)So here's the good news: this level of succintness is coming to Ruby! Matz just merged the following neat trick into Ruby 1.9, letting you write:
burgers.map(&:sauce)Wooo! Count it, "burger" is written only one time! So what's going on here? Well, ":sauce" is a symbol. The trick is that the Symbol class now has a "to_proc" method. Apparently, when a non-Proc object is passed into a method call in the Proc position, it is coerced into a proc using the "to_proc" method. Thus, calling "to_proc" on a symbol now yields a proc that invokes the method with the name of that symbol on the proc's argument. Pretty slick. You can get the code to do this right now at the Ruby Extension project while you wait for Ruby 1.9. However, if you're interested in playing around with "to_proc" in general, here's an example to get you started.
class Cow
def to_proc
return Proc.new{ puts "moo" }
end
end
3.times(&Cow.new)
Pretty cool, huh?
PS- The "&:" prefix is a little line noisy, but I don't feel too bad,
because Common Lisp doesn't nail this either. Because of Common Lisp's
separate function and data namespaces in order to pass the method in,
you need to write:
(mapcar #'sauce burgers)Schemers should feel free to gloat. Or is that (schemers-feel-free-to-gloat)? ;-)
posted on: 06/12/2006 | path: /tech
The Real Problem
I am in receipt of multiple emails, and the target of multiple web links, all saying, in a superior kind of tone, "The poor boy, that primitive Java stuff broke because he doesn't have auto-magical big numbers like Lisp-n-Smalltalk had back in the day." ... [The] "My thought-experiment language solved that in 1976 mantra is boring."My take? Dude, do not taunt the Smalltalkers or the Smalltalk A-Team will come and destroy you. I'd also happily program in a language called "Lisp-n-Smalltalk."
posted on: 06/07/2006 | path: /tech
Selected Links
posted on: 06/03/2006 | path: /tech
No, I want the *deep* copy
Produces a shallow copy of obj.the instance variables of obj are copied, but not the objects they reference. Copies the frozen and tainted state of obj. See also the discussion under Object#dup.Okay, I thought. Since I want a deep copy, I guess I want dup() then. I flipped to the dup() documentation.
Produces a shallow copy of obj.the instance variables of obj are copied, but not the objects they reference. dup copies the tainted state of obj. See also the discussion under Object#clone. In general, clone and dup may have different semantics in descendent classes. While clone is used to duplicate an object, including its internal state, dup typically uses the class of the descendent object to create the new instance.Well crap. That's not it either. There's no built in way to do deep copies in Ruby and that's just silly. A neat trick for working around this that Ben showed me uses Marshal.load(Marshal.dump(obj)) which works for many objects, but not all. According to Ruby Garden this is the Best Known Method. Doh!
posted on: 05/26/2006 | path: /tech
Stupid IRB Tricks
require 'irb/completion'
ARGV.concat [ "--readline", "--prompt-mode", "simple" ]
class Object
def mymethods
(self.methods - self.class.superclass.instance_methods).sort
end
end
The first two lines turn on tab completion. If you don't have this on
already, turn it on now! It only works when IRB can figure out the
type of expressions, but it helps make the interpreter more
friendly. Type []. and hit tab to see the array methods tab
complete.
The second chunk sets up an useful introspection function that Ben and
I came up with. It allows me to type foo.mymethods and get only the
methods that are defined for foo, but not the methods defined in its
superclass, which I find is often what I want (and sorted!). This is
important because sometimes Ruby's humane interface means the number
of methods can be a little overwhelming.
Oh, and one other tip! If you're doing interactive shell scripting in
irb, you'll often get into situations where the huge list of files
you're copying, or text-replacing or whatever is printing after every
command since most Ruby commands return values. Waiting for hundreds
of lines to print after each command can start to drive you nuts.
Thankfully, you can shut off this echoing behavior in irb by typing:
conf.echo = nilThose are all the tricks I can think of, but there must be more out there...
posted on: 05/26/2006 | path: /tech
If It's Not Nailed Down, Steal It
posted on: 05/24/2006 | path: /tech
Using ERB with Camping
def page(name, args={}, &content)
the_binding = binding
name = name.to_s
begin
if name[0] != ?_ && respond_to?(:always)
always()
end
# Let's be safe, even though we're only called by the Controller
throw "Something wicked" if File.dirname(name) != '.'
filename = "#{$BASE}/view/#{name}.html"
file = File.new(filename)
template = file.readline(nil)
erb = ERB.new(template)
result = erb.result(the_binding)
return result if name[0] == ?_
result = page(:_layout) {result} if File.exists?("#{$BASE}/view/_layout.html")
xhtml_strict { result }
rescue => error
xhtml_strict { "Oh dear. Something went wrong: " + error }
end
end
I can't believe I just posted code that bad on the
internet. Eek. Anyways, then in a specific controller, I might write:
class Narmite < R '/narmite/(\d+)'
def get(user_id)
@narmite = User.find user_id
page :narmite
end
end
Note the page :narmite at the end there. The semantics are
simple. Pages are loaded from a views/ directory. So to render
views/foo.html you call page :foo. You can pass
parameters if you need to, and they become available in the args
hash. The layout page can make use of the content block, which can be
called to insert the results of the wrapped pages, like this:
<body> <%= content[] %> </body>Layout follow a simple rule. Pages starting with _ do not get the layout applied to them. Hence the layout page itself is named _layout.html and reusuable HTML chucks always begin with a _. Also, unlike most pages, the always() function is not called before these _ "partials" are run. The always() function is a place to insert code that needs to run before each page render (although, frustratingly, not before each controller call). Partials can then be included in templates like this:
<%= page :foo %>or like this...
<%= page(:foo, :param => value) %>It's pretty hairy, but it let me complete the NARMo site in record time. So don't judge me. =) Next post will be about deploying Camping, which turned out to be harder than I expected. Updated: Lennon points out that web.py has been released into the Public Domain. Fantastic!
posted on: 05/02/2006 | path: /tech
Module in a Class
class Foo module baz end endWell, this makes sense since Class is a subclass of Module (interestingly, classes can also contain classes, something I was also not aware of). But why the hell would you want to do that? I found a really good use for this trick last night while working on Ruby bindings for the Fluidsynth synthesizer.
class Fluidsynth
module C
require 'dl/import'
extend DL::Importable
dlload 'libfluidsynth.dylib'
extern "fluid_synth_t* new_fluid_synth(fluid_settings_t*)"
extern "int delete_fluid_synth(fluid_synth_t*)"
# BLAH BLAH BLAH...
end
def initialize(*soundfonts)
@settings = C.new_fluid_settings
@synth = C.new_fluid_synth(@settings)
@adriver = C.new_fluid_audio_driver(@settings, @synth)
end
# BLAH BLAH BLAH...
end
By putting the C functions loaded through the DL library into a module
named C in my class, I can call them in a concise and natural fashion
that doesn't run the risk of polluting anyone else's namespace.
That's pretty cool! And sorry for knocking Perl, I know a lot of
people love it.
posted on: 04/27/2006 | path: /tech
Exupery
posted on: 04/27/2006 | path: /tech
Jeremy Rocking Out
posted on: 04/26/2006 | path: /tech
Hackers and Painters
- Computer programmers cause a machine to perform a sequence of transformations on electronically stored data.
- Painters apply colored goo to cloth using animal hairs tied to a stick.
I blame Eric Raymond and to a lesser extent Dave Winer for bringing this kind of schlock writing onto the Internet. Raymond is the original perpetrator of the "what is a hacker?" essay, in which you quickly begin to understand that a hacker is someone who resembles Eric Raymond. Dave Winer has recently and mercifully moved his essays off to audio, but you can still hear him snorfling cashew nuts and talking at length about what it means to be a blogger.
posted on: 03/29/2006 | path: /tech
Comp Sci Bands
- Bjarne Stroustrup and the Harvard Architectures
- Alan Kay and the Loop Invariants
- James Gosling and the Traveling Salesmen
- Alonzo Church and the Regular Expressions
- Donald Knuth and the Dining Philosophers
posted on: 03/19/2006 | path: /tech
A Quine Is A Quine Is A Quine
puts <<2*2,2 puts <<2*2,2 2Pretty cute!
posted on: 03/10/2006 | path: /tech
New Blog Software
posted on: 03/08/2006 | path: /tech
Ruby Tuesday
posted on: 03/07/2006 | path: /tech