module Moltrio
  module Config
    class Storage
      def [](key)
        raise NotImplementedError
      end

      def []=(key, value)
        raise NotImplementedError
      end

      def has_key?(key)
        raise NotImplementedError
      end

      def fetch(key, default = Moltrio::Undefined)
        if has_key?(key)
          self[key]
        elsif default != Moltrio::Undefined
          default
        elsif block_given?
          yield
        else
          raise KeyError, key
        end
      end
    end
  end
end

module Moltrio
  module Config
    class Storage
      def [](key)
        raise NotImplementedError
      end

      def []=(key, value)
        raise NotImplementedError
      end

      def has_key?(key)
        raise NotImplementedError
      end

      def fetch(key, *args)
        return self[key] if has_key?(key)
        return args.first if args.size == 1

        raise KeyError, key
      end
    end
  end
end

--- 
+++ 
@@ -13,11 +13,16 @@
         raise NotImplementedError
       end
 
-      def fetch(key, *args)
-        return self[key] if has_key?(key)
-        return args.first if args.size == 1
-
-        raise KeyError, key
+      def fetch(key, default = Moltrio::Undefined)
+        if has_key?(key)
+          self[key]
+        elsif default != Moltrio::Undefined
+          default
+        elsif block_given?
+          yield
+        else
+          raise KeyError, key
+        end
       end
     end
   end
Allow passing a block to Moltrio::Config.fetch to compute a default
