Sorry for the slow response on getting back to you on this; I had to talk to a few people to figure out a good way to handle this.

The concern with this is that it's a bit magical by looking up constants and dynamically called methods. It also tightly couples the kernel to the implementation. For cases like FreeBSD and OpenBSD where the implementation could be shared, it's hard to share the implementation with this method.

I spoke to @zaphod42 and he proposed a few ways to change this.

1) Use an explicit lookup table. Since we already have to require all the implementing files, it's not much more to explicitly map kernels to implementations. 

```ruby
IMPLEMENTATIONS = {
  :FreeBSD  => Facter::Util::Blockdevices::FreeBSD,
  :OpenBSD => Facter::Util::Blockdevices::FreeBSD,
  :Linux        => Facter::Util::Blockdevices::Linux, 
}
```

2) Instead of dynamically fetching the implementation and proxying the method call, the methods could look up the implementing class and then call the method directly on that class.

```ruby

# the names of the methods and variables could be better, but I'm not coming up with anything better right now
def self.implementation_for(kernel)
  impl = IMPLEMENTATIONS[kernel]
  impl ||= NoImplementation
  impl
end

def self.devices
  implementation_for(Facter.value(:kernel)).devices
end
```

This is functionally equivalent to the current implementation but is a lot less abstract.

What do you think of this approach?