{ |one, step, back| } 131 to 140 of 184 articles Syndicate: full/short

Using WEBrick   19 Mar 04
[ print link all ]
Several folks (e.g. Kevin Altis, Aaron Brady) have written about a single line web browser in Python. I wondered what it would look like in Ruby. Here’s one answer…
  ruby -rwebrick -e 'WEBrick::HTTPServer.new(:Port=>8000,:DocumentRoot=>".").start'

Since WEBrick defaults to port 80 and doesn’t use the current directory as the document root by default, we have to add that information to the command line.

Although interesting, I find the following script more useful than a single line command. I often generate HTML docs on a machine at work that doesn’t have a web server, nor file system that is available to my browser’s "file:" protocol. So I fire up the "servefiles.rb" script below.

  #!/usr/local/bin/ruby
  require 'webrick'
  include WEBrick

  dir = Dir::pwd
  port = 12000 + (dir.hash % 1000)

  puts "URL: http://#{Socket.gethostname}:#{port}"

  s = HTTPServer.new(
    :Port            => port,
    :DocumentRoot    => dir
  )

  trap("INT"){ s.shutdown }
  s.start

Notice that the port is calculated from a hash function on the directory name. This allows me to run multiple mini-webservers in different directories. The script prints out the URL (with port number) when it starts, so I just cut and paste the URL into the browser to see the served files.

How do you use WEBrick?


comments

Pretty Rublogs   19 Mar 04
[ print link all ]
I see a number of Rublog users have upgraded their blogs look and feel. (See Dave Thomas, Chad Fowler and Glenn Vandenburg). It leaves this site looking a wee bit plain now.

Hey Guys! Care to share your template and CSS files?


comments

RubyGems Alpha 0.2.0 Released   19 Mar 04
[ print link all ]
I grabbed the latest version of RubyGems and typed:
    traken$ sudo gem --remote-install log4r
    Successfully installed log4r version 1.0.5

With one command, log4r was downloaded and installed without hassle or fuss. This is way cool.

There is a lot of work to be done on RubyGems, but making Ruby project installations this easy is great.


comments

Some Pointers   13 Mar 04
[ print link all ]
I have not updated this Blog for over a month. It has been real busy around here. I have some ideas I want to share, but I think I’ve run afoul of Charles Miller’s #1 blogging rule. So I’m just going plunge into this posting by pointing out a couple of interesting reads I’ve found lately.

But First, Some Apologies

Yes, my site was down for a few days in February. I didn’t notice it right away, and when someone at work pointed out they couldn’t get to onestepback.org I had to wait to fix it until I got home. Even then, I thought it was only down for the day. It wasn’t until I reviewed the web stats for February did I realize that it was down for at least three days.

Sorry. It turns out that the copy of apache servicing http requests had crashed and burned. The ssl server was still up so remote access to my mail was OK. I just didn’t notice that the http server was down (see, I really was busy). Nevertheless, we now have some monitoring software in place so simple crashes shouldn’t cause extended outages any more.

Directing VS Enabling

Static verses Dynamic Typing. Checked verses Unchecked Exceptions. The battle rage on (and I’ve taken part in my share of them). Martin Fowler has some keen insight into the nature of the proponents of each side of the debate. He calls it the difference between a Directing attitude and an Enabling attitude. Directors wish to make the computing environment as safe as possible and willing accept restrictions to achieve that goal. Enablers desire flexibility above (in their view unneeded) safety, and will chaffe unagainst restrictions. Read Martin’s writeup, he explains it much better than I do.

I’ve landed on both sides of the debate in the past. Lately I’ve found myself on the enabler side of the equation more often than not.

When Generic’s Aren’t

Bruce Eckel has some surprising insight on the use of generics in Java (available in Java 1.5). For those who enjoy the ad-hoc polymorphism available in C++ generics are going to be surprised by Java’s version. If Eckel is correct, then generics look like they will be great for making generic containers and little else.

See Bruce’s article for details.

And More on Latent Typing

Speaking of the Static/Dynamic typing debate, the feedback page for Eckel’s Generics article, a commenter is defends the need for interfaces with the following comment:

In java, the symantics of a method are not bound to its name, so much as they are bound to the interface the method belongs to.

Bruce responds with a followup article on Latent Typing, but I would like to add my two cents here.

Java interfaces are more about syntax than semantics. They insure that implementing classes have the proper methods defined with the proper number and type of arguments, and that the methods actually do return a value of the appropriate type. But that’s it. Interfaces do nothing to support any meaningful semantics about the methods.

If you are interested in language support for semantics, I suggest you take a look at Eiffel. When you define a interface in Eiffel (which Eiffel would call a deferred class), you not only specify the argument list for the method, you also specify the promises to which the method implementor must adhere. This set of promises (the semantics) is called a contract and leads to the concept of Design by Contract.

Even if you never program a line of Eiffel code, understanding Design by Contract is a useful skill for a developer.

Speaking of Design by Contract

And that leads us to our final posting. Artima has published a series of interviews with Bertrand Meyer, the designer of Eiffel and Design by Contract. The interviews are worth reading (here is part 4, you can find links to the other parts from there).

I find that I don’t always agree with Meyer, but when I do disagree, I think through my position very carefully.

All for Now

I’ve run out of time. Hopefully it won’t be so long before I post again.


comments

Writing an RCR   31 Jan 04
[ print link all ]
Matz is accepting RCRs (Ruby Change Requests) for Ruby 2.0 and Rite until the end of March. Tell the truth, is there something in Ruby that you wished worked a little differently? If so, now is your chance to stand up and be counted.

The Ruby Nuby Syndrome

I’ve noticed a trend on the ruby-talk mailing list. A nuby appears on the list, likes the language, except for one minor nit. Wouldn’t it be nice if Ruby would do (insert fix for minor nit here). A nit might be Ruby’s lack of overloaded functions, static typing, explicit interfaces, or anything else in Language X that is different in Ruby.

Now there is nothing wrong with static typing or interfaces. It is just that these topics have been hashed out on ruby-talk over and over again.

How Ruby Sucks

Don’t get me wrong. Ruby isn’t perfect by any means. In fact, I thought the Matz’s Keynote speech at the 2003 RubyConf was particularly healthy. Matz titled his talk "How Ruby Sucks" and then detailed the direction Ruby was moving for version 2.0.

And now that the features of Ruby 2.0 are beginning to solidify in Matz’s mind, he is encouraging Ruby Change Requests (RCRs) to be submitted through March at the RCRcive.net site.

But before you go and write up your favorite change request, consider the following.

Before You Write an RCR

Before you write an RCR, make sure you cover the following bases.

  1. Research. Has this change been requested before? Search the ruby-talk archives (Google is your friend). Also read the list of RCRs, both current and legacy entries to see if there are similar RCRs. Be sure to read and understand any issues raised during any previous discussions.
  2. Investigate. What would it take to implement your RCR. Can you simulate it with Ruby code today? What are the tradeoffs? Are there performance issues? Are there complexity issues? What about backwards compatibility?
  3. Solicit Feedback. If your suggestion is way out there, perhaps it would be wise to get feedback before you write up your RCR. It wouldn’t hurt to post a message on ruby-talk saying "I’m considering writing an RCR on XYZ, am I on track here?". Many ruby-talk members are tired of the same-old changes being discussed over and over again, but if you’ve made it past the research and investigate phase, a ruby-talk message would not be out of line. The feedback you get may help you tighten up the RCR.

Writing the RCR

Once you are ready to actually write the RCR, do the following

  1. Read the Submission Guidelines and Suggestions for submitting an RCR.
  2. Fill out each section of the RCR submission form. Pay special attention to the purpose of each section. The RCR submission help page goes over the sections, so I won’t repeat the information here.
  3. Remember the purpose of the RCR is to convince Matz and other Rubyists that they would benefit from your proposed language change. Clearly lay out what the perceived problem is and exactly how your proposal addresses that problem. Don’t skimp in the Analysis section, but carefully layout both the pros and cons to your RCR. Good, compelling examples are worth their weight in gold.
  4. If there is any way possible, provide an implementation of your suggestion. If your suggestion cannot be done in the current version of Ruby, approximate it as best you can. If you can’t provide a full speed implementation, provide a slow one (but include performance analysis as appropriate). Working code speaks much louder than vague suggestions.
  5. Don’t bother to invoke POLS (Principle of Least Surprise) as a justification for the RCR. Matz is the final arbiter of what is surprising and what is not, and telling him what his expectations are will not advance your position.

After You Write Your RCR

  1. Go back to review and comment on other RCRs. Make sure you vote too. But remember, the voting is only there to provide Matz with some indication of the interest in a given feature. This isn’t a democracy, Matz still makes the final call.
  2. Listen to feedback on your RCR. Several RCRs have already been withdrawn or rewritten based on the feedback provided by the RCR process.

It’s an exciting time for Rubyists, we are beginning to get a picture of what Ruby 2.0 might be like. So if you have an RCR in mind, please go ahead and submit it.

Just make sure you do the homework too.


comments

Saw this ...   23 Jan 04
[ print link all ]
in a UseNet signature:
  A: No.
  Q: Is top-posting okay?

comments

A Little Ruby, A Lot of Objects   23 Jan 04
[ print link all ]
It was my junior year in college and the math course I intended to take wasn’t offered that semester. My advisor recommended a computer programming course. He said "It will be useful, and who knows, you may like it." (Little did he know!). So that’s how I signed up for an introductory class on FORTRAN.

When I got to the first lecture, the instructor kept writing code snippets on the blackboard and asking questions about them. Now I knew a enough FORTRAN to do simple plots for my physics lab courses, but the code on the blackboard had way too many parenthesis to be FORTRAN.

Here’s one example (from memory):

  (DE MEMBER (PIP DECK) (COND
      ((EQ PIP (CAR DECK)) T)
      (T (MEMBER PIP (CDR DECK)))))

(And yes, the layout is accurate. The COND was definitely on the first line. At this point in the class, it was explained as required "magic".)

"What kind of programming language is this?" I thought. It didn’t make any sense for about 3 days. And then I had the "Ah-HA!" experience and everything fell into place. I finally "got it", and fell in love with Lisp and programming in general from that point on.

The instructor for the course was Daniel Friedman, the author of the book "The Little Lisper" (which was one of the required books for the course). The Little Lisper emulated, in print, Professor Friedman’s style of teaching, revealing a little bit of information through a question and answer session until the reader/student gains enough understanding to put all together.

Brian Marick has started a book where he emulates that Q&A style, but targets the book at Object Orientation and Ruby instead of Lisp. You can find the first three chapters of A Little Ruby, A Lot of Objects at www.visibleworkings.com/little-ruby. In those three short chapters he introduces objects, messages, protocols, inheritance, classes and meta-classes to a beginning programmer in a whimsical manner, similar to the original Lisp book. It was a delight to read the step by step approach used in the book.

The only downside is that Brian seems to have stopped after three chapters. Nevertheless, if you are looking for a gentle introduction to object orientation in general and Ruby in particular, take a look at A Little Ruby, A Lot of Objects.


comments

Another Ruby Build System   21 Jan 04
[ print link all ]
Jon writes about a build system he put together using Ruby. Scripts in Jon’s system look alot like normal programs. Tasks are defined like a normal Ruby method, but a target_method command marks that method as special. These special commands are only executed once, no matter how many times they are called.

It’s a clever and remarkably simple approach.

Jon also describes a technique he uses to interface with ant to build a Java program. Details are a little sketchy, but I wonder if it is something that could be used with Rake.


comments

Eckel and Fowler on Build Systems   08 Jan 04
[ print link all ]
Build systems seem to be at the forefront of everyone’s mind recently. Bruce Eckel and Martin Fowler have recently commented on the topic.

Bruce Eckel on Build Systems

In "Why We Use Ant", Bruce argues why we should continue use Ant, even though it has some significant flaws as a build system for large, complex projects. His arguments are:

  1. It’s never as easy as it seems [writing a replacement for Ant].
  2. It’s probably not the battle you should be fighting.
  3. Lots of people have tried and failed.
  4. Politics matter.

Number four is actually a very strong argument, especially in a group doing Java development.

Let me quote an interesting passage in Bruce’s article.

Another important proglem with Ant is that its XML-influenced declarative syntax is limited. A build system is really a little computer program. Normally, you look for conditions (a source file is out of date with its target is the primary one for make) and you execute commands, but sometimes you need to do things that are more sophisticated, conditional logic, that kind of thinkg. Both make and Ant fall down here because, while it’s possible to do these things it suddenly gets a lot more complicated because that’s not normally what they do.

Exactly! It was my need to dynamically generate some make targets that started my original make rant that sparked the rake project. make, by itself, just wasn’t up to the task

Bruce continues …

I suppost if I were give a budget and a bevy of programmers, I would ask them to take make, which is open-source, eliminate the silly tab-vs.-space thing, and meld it together with Python, also open-source. make would only retain the simplest of its functionalites (primariy the way you set up dependencies and execute simple commands), and as soon as you wanted to do something more complex you’d be able to drop seamlessly into Python syntax, using any Python libraries you want. I think that would probably be my dream build system.

Bruce, you really need to check out rake. Its exactly what you describe above (well, if you substitute Ruby for Python). And it didn’t take a bevy of programmers. The core functionality was an evening’s worth of work.

Dropping seamlessly into Ruby is trivial, because a Rakefile is a Ruby program, specified in standard (although idiomatic) Ruby syntax. Since we never leave Ruby, we have no parsers to deal with, leaving a very small code base for the core functionality. The core of Rake (dependency management, task execution and rule matching) is less than 200 lines of code. The minimal rake install (a single file) is around 500 lines of Ruby code and adds common file commands (system independent versions of cp, rm, mv, etc.) and a flexible FileList object that mimics Ant’s include and exclude semantics.

Martin Fowler on Build Systems

Martin Fowler echos many of Bruce’s comments and reiterates that a build system really needs a full blown programming language. Martin has been dabbling in Ruby, and it seems that he has discovered rake and has been using in it some small projects. Great!

A Build Language Needs to be a Programming Language

Why should your build system support a full blown programming language? Here is one small example taken from a real situation at work.

When we are ready to install a project at work, we create a staging directory containing the files to be installed into an environment (e.g. testing or production). As problems are discovered in testing, corrections are made in a development area and copied to the staging directory for reinstallation.

The following makefile copies 2 jar files from the developement area to the staging area. Yes, I know that a makefile is probably overkill for this problem, but in real life there are other tasks as well. For example, using make (or rake) allows me to ensure that a refresh step always occurs before an install step, but only if the refresh is needed.

So here is the makefile …

  # Makefile to copy jars

  DEV=/home/jim/development
  JARDIR=jars

  refresh: $(JARDIR)/a.jar $(JARDIR)/b.jar

  $(JARDIR)/a.jar: $(DEV)/AProject/lib/a.jar $(JARDIR)
          cp $@(DEV)/AProject/lib/a.jar $@

  $(JARDIR)/b.jar: $(DEV)/BProject/lib/b.jar $(JARDIR)
          cp $(DEV)/BProject/lib/b.jar $@

  $(JARDIR):
          mkdir -p $(JARDIR)

Notice that there are several duplications in the file. The copy command for the two jar files are remarkably similar, yet different enough that you can’t capture both cases with a generic make rule. Also, knowledge about a particular jar file is spread out in two places; once in the copy rule itself, and again in refresh task line.

First we will translate the above Makefile into an equivalent Rakefile. See the Rakefile documents for details on the syntax of a Rakefile.

  # Rakefile translated directly from the Makefile

  DEV = "/home/jim/development"
  JARDIR = "jars"

  task :refresh => [ "#{JARDIR}/a.jar", "#{JARDIR}/b.jar" ]

  file "#{JARDIR}/a.jar" => [ "#{DEV}/AProject/lib/a.jar", JARDIR ] do |task|
    cp "#{DEV}/AProject/lib/a.jar", task.name
  end

  file "#{JARDIR}/b.jar" => [ "#{DEV}/BProject/lib/b.jar", JARDIR ] do |task|
    cp "#{DEV}/BProject/lib/b.jar", task.name
  end

  directory JARDIR

All the duplication from the original makefile still exists in the rake version. Lets remove it by writing a function that will generate the dependency (and copy command) based on the jar file name and the project name.

  # Rakefile with (some) redundencies removed

  DEV = "/home/jim/development"
  JARDIR = "jars"

  task :refresh
  directory JARDIR

  def make_jar_copy_task(jarname, project)
    stagejar = "#{JARDIR}/#{jarname}.jar"
    devjar   = "#{DEV}/#{project}/lib/#{jarname}.jar"

    task :refresh => [ stagejar ]

    file stagejar => [ devjar, JARDIR ] do
      cp devjar, stagejar
    end
  end

  make_jar_copy_task("a", "AProject")
  make_jar_copy_task("b", "BProject")

Notice that the refresh task is now declared without any explicit dependencies. The individual jar file dependencies are added to the refresh task inside the make_jar_copy_task function.

If we had a lot of jar files, we could put them in an explicit list and replace the last two lines with something like this …

  jarfiles = [ ["a", "AProject"], ["b", "BProject"], ["c", "CProject"] ]
  jarfiles.each { |jar, proj|  make_jar_copy_task(jar, proj) }

Or perhaps we have to deduce the jar files from the current contents of the JARDIR directory. (Assume that projects is a lookup table mapping jarfiles to project names.)

  Dir["#{JARDIR}/*.jar"].each { |jar|
    jarname = File.basename(path).sub(/\.jar$/, "")
    make_jar_copy_task(jarname, projects[jarname])
  }

Or perhaps we need to pull our jar file names from a database …

  DBI.connect(DBI_STRING, USER, PASSWORD) do |db|
    sql = "SELECT jarfile, project FROM install_table WHERE install_date = ?",
    db.select_all(sql, INSTALL_DATE) do |row|
      make_jar_copy_task(row['jarfile'], row['project'])
    end
  end

Ok, that last example might have been a little over the top. The point is that builds can become arbitrarily complex, and anything less than a full programming language is just doesn’t cut it.


comments

Variable Bindings in Ruby   23 Dec 03
[ print link all ]
In the Shoeboxes article I argued that a mapping of names to values is a better mental model for variables than the shoebox model. How can we take advantage of explicit bindings?

Bindings

In Ruby, bindings are explicitly made available in a Binding object. Invoking the binding method will produce a Binding object for the current local variables.

Given that bindings are objects, one would think that there would be a number of methods available to get, set and query the names and their values. Unfortunately, in Ruby that is not the case. When you pass a binding to eval, Ruby will use the binding to resolve open variable references while evaluating a string. Other than that, bindings are pretty opaque.

But that still gives us some useful functionality. If you want to know the value of a variable in binding, just evaluate the variable name …

  eval "a", vars         # Evaluate the value of "a" in the binding "vars"

To change a variable’s value in a binding, use …

  eval "a = 101", vars   # Bind "a" to the value 101.

Bindings and Local Scope

Using the binding method, we can capture the variable bindings available at a particular point in the code, and pass that binding to a different part of the code to be used there.

Here we pass the binding of the current scope to a method that uses it. This is pretty straight-forward.

  def value_of_a(vars)
    eval "a", vars
  end

  def my_scope
    a = 33
    value_of_a(binding)
  end

  my_scope               # => 33

Bindings can be returned from a function as well. This example shows that a binding continues to exist after the function that defines the binding has exited.

  def f
    a = 22
    b = 33
    binding
  end

  f_vars = f()

  eval "a", f_vars         # => 22
  eval "b", f_vars         # => 33
  eval "a = 101", f_vars
  eval "a", f_vars         # => 101

The bizzare feature of this example shows that not only does binding persist beyond the scope of the function that created them, but that you can modify these bindings just by evaluating an assignment within their context.

Blocks and Bindings

A block in Ruby is a chunk of code that can be called like a function. The block automatically carries with it the bindings from the code location where it was created. For example …

  a = 33
  block = lambda { a }
  def redefine_a(b)
    a = 44
    b.call
  end
  redefine_a(block)      # => 33

The block returns the value of a in the binding where the block was defined (a == 33), not the binding where the block was called (a == 44).

This combination of code block and binding is called a closure, and is a very powerful tool in a Ruby programmers toolbox.

Swapping Values

Recently on the ruby-talk mailing list, someone asked about writing a swap function where swap(a,b) would swap the values of the variables "a" and "b". Normally this cannot be done in Ruby because the swap function would have no reference to the binding of the calling function.

However, if we explictly pass in the binding, then it is possible to write a swap-like function. Here is a simple attempt:

  def swap(var_a, var_b, vars)
    old_a = eval var_a, vars
    old_b = eval var_b, vars
    eval "#{var_a} = #{old_b}", vars
    eval "#{var_b} = #{old_a}", vars
  end

  a = 22
  b = 33
  swap ("a", "b", binding)
  p a                          # => 33
  p b                          # => 22

This actually works! But it has one big drawback. The old values of "a" and "b" are interpolated into a string. As long as the old values are simple literals (e.g. integers or strings), then the last two eval statements will look like: eval "a = 33", vars". But if the old values are complex objects, then the eval would look like eval "a = #<SomeObject:0x401fef20>", vars. Oops, this will fail for any value that can not survive a round trip to a string and back.

Blocks as Getters and Setters

Let’s try a different approach to the "swap" problem. Instead of passing variable names and bindings to the swap function, let’s pass closures that do the work for us …

  def swap(get_a, get_b, set_a, set_b)
    temp = get_a.call
    set_a.call(get_b.call)
    set_b.call(temp)
  end

  a = 22
  b = 33
  swap(lambda{a}, lambda{b}, lambda{|v| a=v}, lambda{|v| b=v})
  p a           # => 33
  p b           # => 22

Wow! This works great! The values are swapped and arbitrary values are supported. The only down side is that the call to swap is extremely verbose.

Abstracting the Getter/Setter Code

We can shorten this by creating a getter/setter abstraction called a reference. To create a reference, we will need to supply the name of a variable along with a binding. But this is what we want the code to look like.

  a = 22
  ref_a = Reference.new(:a, binding)
  p ref_a.value        # => 22
  ref_a.value = 33
  p ref_a.value        # => 33
  p a                  # => 33

So changing the value of a reference should change the binding of the variable the reference refers to.

Here is a first pass at writing the Reference class …

  class Reference
    def initialize(var_name, vars)
      @getter = eval "lambda { #{var_name} }", vars
      @setter = eval "lambda { |v| #{var_name} = v }", vars
    end
    def value
      @getter.call
    end
    def value=(new_value)
      @setter.call(new_value)
    end
  end

Note that we create lambdas to handle the getting and the setting of values. This avoids the string interpolation problem mentioned above. Since we create the lambdas in the scope of the initialize fuction, we need to explicity pass in the calling scopes bindings so that the lambdas are created in the environment where are variables are defined. Leaving off the binding to eval will cause our getter and setter lambdas to modify the values of "a" and "b" in the scope of initialize instead of the calling scope.

Writing Swap

We are almost ready to write our swap function. First, let’s create a utility function (named ref) for creating references.

  def ref(&block)
    Reference.new(block.call, block.binding)
  end

ref takes a single block that returns the name of the value we are refering to. Since blocks automatically carry their binding with them, we get both the variable name and binding in a single argument. We use ref like this …

   aref = ref{:a}

Now swap can be written like this.

  def swap(aref, bref)
    aref.value, bref.value = bref.value, aref.value
  end

  a = 22
  b = 33
  swap(ref{:a}, ref{:b})
  p a                       # => 33
  p b                       # => 22

Summary

Using bindings, blocks and closures, we can have a great deal of control over the binding of names to objects within any scope. The basic ideas for the Reference class were developed in response to a Scheme/Python question on the C2 Wiki (see c2.com/cgi/wiki?SinisterSchemeSampleInRuby).


comments

 

Formatted: 14-Oct-08 10:10
Feedback: jim@weirichhouse.org