UPnP-IGD 1.0.0

Eric Hodel | Mon, 30 Jun 2008 06:45:00 GMT

UPnP-IGD version 1.0.0 has been released!

UPnP-IGD is a UPnP extension for Internet Gateway Devices that displays information about the device. UPnP-IGD is an example of the use of some UPnP APIs.

UPnP-IGD comes with the upnp_igd utility which outputs information like this:

Gateway at http://10.1.1.1/
Connected, up since 2008-06-29 03:31:00 (66123 seconds)
Connection type: IP_Routed
384 Kb/s up, 1536 Kb/s down
External IP address: 10.255.255.254

Port mappings:
0 UDP *:4502  -> 10.1.1.2:4500  "iC4502"
1 UDP *:5355  -> 10.1.1.2:5353  "iC5355"
2 UDP *:58712 -> 10.1.1.3:58712 "Skype UDP at 10.1.1.3:58712 (546)"
3 TCP *:58712 -> 10.1.1.3:58712 "Skype TCP at 10.1.1.3:58712 (546)"
4 UDP *:5353  -> 10.1.1.4:5353  "iC5353"

Unfortunately, UPnP-IGD does not allow anything to be set on the device, and has only been tested against miniupnpd.

Posted in ,  | no comments

UPnP 1.0.0

Eric Hodel | Mon, 30 Jun 2008 06:09:00 GMT

UPnP version 1.0.0 has been released!

UPnP-1.0.0 is an implementation of the UPnP protocol. The 1.0 release:

  • Discovers UPnP devices and services via SSDP, see UPnP::SSDP
  • Creates a SOAP RPC driver for discovered services, see UPnP::Control::Service
  • Creates concrete UPnP device and service classes that may be extended with utility methods, see UPnP::Control::Device::create, UPnP::Control::Service::create and the UPnP-IGD gem.
  • Does not support eventing
  • Does not support server creation

UPnP comes with upnp_discover which searches for UPnP devices and dumps information about them and upnp_listen which will listen for device notifications.

Posted in ,  | 3 comments

Gem Dependencies

Eric Hodel | Mon, 23 Jun 2008 22:28:40 GMT

I was chatting with Yehuda Katz, and somehow we ended up talking about speed:

Eric Hodel: I don’t worry about inheritance

Eric Hodel: or speed, for that matter

Yehuda Katz: heh

Yehuda Katz: that’s why you wrote RubyInline?

Eric Hodel: Ryan wrote RubyInline because, roughly, “How hard could it be?”

Eric Hodel: and an intense hatred of C

This got me thinking, how long did it take from RubyInline to be written until it was actually used? The RubyGems answer is 151 days, and by ParseTree, but RubyInline is actually about 2 years older than its gem, first committed on 2002/09/05.

To figure this out, I wrote a script that walks all the gems and figures out when a gem was first released, when a gem was first mentioned in a dependency, and the time between the two. Today, the figures are:

681 of 3234 gems used as dependencies (21%)
average time to first use is 148 days
maximum time to first use is 1332 (dnssd)

You can get the full output in the gem dependency report (which updates weekly), and download the gem dependency script too.

Posted in ,  | no comments

Static Typing for Ruby

Eric Hodel | Wed, 16 Apr 2008 23:36:00 GMT

Last week I went to a presentation by Jeff Foster about Diamondback Ruby (DRuby), a static type inferencer for Ruby. DRuby's goals are to be simple to use, be flexible enough to handle common ruby idioms, be reasonably useful, and to revert to run-time type checking as needed.

DRuby features its own GLR parser for Ruby grammar with extensions for type annotations and is written in OCaml. Internally it uses a normalized and simplified ruby subset to perform the type analysis in order to remove ambiguities and simplify flow analysis.

Type inference is fed a prebuilt set of type annotations derived from the core library that look very similar to rdoc. The annotation system can handle variable arguments to methods, type intersections and type unions. Basically, this means it's expressive enough to handle String#slice which can be called six different ways.

For details on the type inferencing itself, you should read the paper. There are currently some limitations in DRuby, among them are unsuitability for large applications due to time constraints and too many false positives, it flattens namespaces such that A::C and B::C are considered the same, and it doesn't handle #eval.

On a set of eight benchmark applications, five required some minor modifications for DRuby to operate (described in the paper), and three of the eight had false positives. I found two of the false positives interesting, as I think the code highlighted by DRuby is questionably written.

The false positive in sudokosolver is from a method that returns an Array or false then performs a run-time type check to do the appropriate thing with the results. The false positive in ObjectGraph involves a String that is duck-typed into a StringIO if StringIO wasn't required through a singleton class.

Compared to other static typing add-ons for Ruby, this is the most promising one I've seen. There's no type annotations required to muck up my existing applications (they would be provided with DRuby), no penalties for checking at run-time, and it's smart about functions as convoluted as String#slice.

Unfortunately, since it hasn't been released into the wild yet (the target date we were given was sometime this summer) it's hard to say if it how useful it would be. Judging from the two false positives given, it may have some utility as an equivalent to a flog, though.

Posted in  | 5 comments

3000 Gems

Eric Hodel | Mon, 14 Apr 2008 22:39:12 GMT

Earlier this month the 3000th gem was released! Here’s how the repository has grown since its early days:

Gem counts 2008-03

Posted in ,  | 2 comments

An RDoc Wiki

Eric Hodel | Fri, 15 Feb 2008 00:14:37 GMT

For fun, I wrote a 200 line wiki a couple of weeks ago using WEBrick and RDoc withRCS as the only external dependency for history. You’ll need a recent build of Ruby 1.9 or Rubinius to run it:

rdoc_wiki.rb

It uses RDoc’s markup for formatting, and stores its content into ~/.rdocwiki as plain text files.

RdocWiki has one special page, /WikiCss that you can use to style things, here’s what I used:

#wiki_edit textarea {
  width: 40em;
  height: 20em;
}
#wiki_edit input {
  display: block;
}
#wiki_restore {
  display: inline;
}

I’d run a copy on Rubinius for you to use, but currently Rubinius is broken on FreeBSD.

Posted in ,  | no comments

RDoc's TemplatePage removed from Ruby

Eric Hodel | Mon, 07 Jan 2008 10:59:54 GMT

If you’ve got a custom RDoc template, it won’t work with the next release of 1.9. I’ve removed the custom TemplatePage and replaced it with an ERB-based version that works similarly.

This should make it much, much easier to write a custom RDoc template as you can now use arbitrary ruby code inside your templates.

It’s really easy to convert an old RDoc template to the upcoming version:

Replace thisWith this
%blah%<%= values["blah"] %>
!INCLUDE!<%= template_include %>
HREF:aref:name<%= href values["aref"], values["name"] %>
IF:blah<% if values["blah"] then %>
IFNOT:blah<% unless values["blah"] then %>
ENDIF:blah<% end %>
START:blah<% values["blah"].each do |blah| %>
END:blah<% end %>

To make nested loops easier to convert, convert START statements to:

<% values["blah"].each do |blah| $stderr.puts blah.keys %>

So you can see what is being used inside which loop.

I’ve also removed the old_html template, as I don’t think anybody uses it anymore, and updated all the existing templates in RDoc to use ERB. (If somebody could double-check my work on the CHM and XML outputters, that would be great.)

Posted in ,  | 11 comments

OptionParser Argument Casting

Eric Hodel | Sun, 06 Jan 2008 04:56:03 GMT

OptionParser is a command-line argument parsing library for Ruby that provides several really nice features. Using OptionParser tends to be verbose, but it is also very flexible. One of it’s features that I really like is argument casting.

Argument casting allows you to validate a command-line option and convert it from the user-supplied String into whichever object you like. The ri for OptionParser has an example similar to this one for casting a floating-point argument into a Float value:

require 'optparse'

options = {}

opts = OptionParser.new do |opts|
  # Cast 'delay' argument to a Float.
  opts.on("--delay N", Float,
          "Delay N seconds before executing") do |n|
    options[:delay] = n
  end
end

opts.parse! ARGV

p options

The second argument to opts.on, Float, tells OptionParser to cast the option’s value to a Float before passing it to the handler block. When you run this example with a number as the argument, you’ll see the value in options is a Float:

<samp>$ ruby op_test.rb --delay 1
{:delay=>1.0}</samp>

If you pass a value that can’t be cast into a Float an OptionParser::InvalidArgument is raised:

<samp>$ ruby op_test.rb --delay X
[...]/optparse.rb:454:in `parse': invalid argument: --delay X (OptionParser::InvalidArgument)
    [...]
    from [...]/optparse.rb:1353:in `parse!'
    from op_test.rb:13</samp>

You can rescue this and provide an appropriate help message.

At the bottom you’ll find some tables of the various casts that are built-in to OptionParser. If none of those do what you want, writing your own is very easy.

In RubyGems, various arguments are automatically cast to the appropriate objects. For example, when you specify a version with `gem install—version ’= 1.2.3’`, the argument ’= 1.2.3’ is turned into a Gem::Requirement:

OptionParser.accept Gem::Requirement do |value|
  Gem::Requirement.new value
end

Gem::Requirement.new knows how to cast a String and raises an exception if it can’t, so we delegate to it to do the work.

If you only want to have a specially formatted string, you can provide a regular expression instead. The DecimalInteger cast is defined like this:

DecimalInteger = /\A[-+]?\d+(?:_\d+)*/io
accept(DecimalInteger) {|s,| s.to_i if s}

So the pattern referenced by the name is used to validate the argument.

You can also provide a pattern as the second argument. The Float cast is defined like this:

floatpat = %r"\A[-+]?[...]"io
accept(Float, floatpat) {|s,| s.to_f if s}

Notice that for each of these, you still need to turn the string argument into the appropriate object.

OptionParser Built-in Casts

With no extra requires, OptionParser can cast the following arguments for you:

NameRequirementsCast to
Object, NilClassAny string, no conversionString
StringAny non-empty stringString
IntegerBinary (0b), octal (0), hexadecimal (0x), or decimal numberInteger
FloatFloating point numberFloat
NumericGeneric number formatFloat for floats, Integer for integers
OptionParser::DecimalIntegerDecimal integerInteger
OptionParser::OctalIntegerOctal, binary or hexadecimal numberInteger
OptionParser::DecimalNumericDecimal numberInteger or Float
TrueClass+, -, yes, no, true, false, niltrue or false, defaults to true
FalseClass+, -, yes, no, true, false, niltrue or false, defaults to false
ArrayComma-separated listArray of Strings
RegexpRegular expression with optionsRegexp

If you require ‘optparse/date’:

NameRequirementsCast to
DateTimeAnything handled by DateTime.parseDateTime
DateAnything handled by Date.parseDate

If you require ‘optparse/shellwords’:

NameRequirementsCast to
ShellwordsAnything handled by Shellwords.shellwordsArray of Strings

If you require ‘optparse/time’:

NameRequirementsCast to
TimeAnything handled by Time.parseTime

If you require ‘optparse/uri’:

NameRequirementsCast to
URIAnything handled by URI.parseURI

Posted in  | 2 comments

RubyConf 2007

Eric Hodel | Tue, 20 Nov 2007 00:32:50 GMT

I had a good time at RubyConf, but was too busy obsessing over my presentation. I think it turned out well, though, as many people complimented me on my talk. I did manage to play my “you owe me a beer” card a couple times though, which was good.

Oh, yes, here’s my slides for Maximizing Productivity in PDF, the Keynote (zipped) form, and the presentation courtesy of Confreaks.

This RubyConf had the feel of the pre-Rails RubyConfs, which was very welcome. The dual track format was alright, except that one talk would be far more popular than the other leaving one room standing-room-only.

I think my favorite talk of the conference was Ben Bleything’s Controlling Electronics with Ruby, because he had all sorts of fun toys to pass around and play with.

Also, Rich Kilmer, Akira Tanaka and Koichi Sasada figured out the last issues to importing RubyGems into 1.9, so we’ll be cleaning that up over the next week or two. I’ll have a separate post on the RubyGems differences between 1.8 and 1.9 shortly.

Posted in ,  | 1 comment

Time.today going away

Eric Hodel | Mon, 08 Oct 2007 22:22:32 GMT

So you’ve been using Time::today for some time, and thought it was part of time.rb or ActiveSupport? Well, you’d be wrong. I was!

It turns out that rubygems/specification.rb defines Time::today, and that’s wrong. RubyGems has no business adding methods to the core when it doesn’t need to, so I’ve marked it for removal.

If you want to use Time::today in the future you’ll need to define it in your code somewhere, here is its definition:

require 'time'

def Time.today
  t = Time.now
  t - (t.to_i % 86400)
end unless Time.respond_to? :today

Go ahead and throw it in wherever you think is appropriate. I suggest you do this now.

UPDATED: Now with a better Time::today.

Posted in ,  | 6 comments

Older posts: 1 2 3 ... 8