diff --git a/lib/data_uri.rb b/lib/data_uri.rb index 42dc655..515f515 100644 --- a/lib/data_uri.rb +++ b/lib/data_uri.rb @@ -1,24 +1,7 @@ require 'uri' require 'base64' +require 'stringio' +require 'rubygems' +require 'mime/types' -module URI - - class Data < Generic - - COMPONENT = [:scheme, :opaque].freeze - OPAQUE_REGEXP = /^([^;]+);base64,(.+)$/.freeze - - attr_reader :content_type, :data - - def initialize(*args) - super(*args) - if OPAQUE_REGEXP.match(@opaque) - @content_type = $1 - @data = Base64.decode64($2) - end - end - end - - @@schemes['DATA'] = Data - -end +require 'data_uri/uri' diff --git a/lib/data_uri/open_uri.rb b/lib/data_uri/open_uri.rb new file mode 100644 index 0000000..b485c79 --- /dev/null +++ b/lib/data_uri/open_uri.rb @@ -0,0 +1,22 @@ +module URI + + class Data + + def open + io = StringIO.new(data) + OpenURI::Meta.init(io) + io.meta_add_field('content-type', content_type) + if block_given? + begin + yield io + ensure + io.close + end + else + io + end + end + + end + +end diff --git a/lib/data_uri/uri.rb b/lib/data_uri/uri.rb new file mode 100644 index 0000000..a741103 --- /dev/null +++ b/lib/data_uri/uri.rb @@ -0,0 +1,33 @@ +module URI + + class Data < Generic + + COMPONENT = [:scheme, :opaque].freeze + + attr_reader :content_type, :data + + def initialize(*args) + super(*args) + @data = @opaque + if md = MIME::Type::MEDIA_TYPE_RE.match(@data) + offset = md.offset(0) + if offset[0] == 0 + @content_type = md[0] + @data = @data[offset[1] .. -1] + end + end + @content_type ||= 'text/plain' + if base64 = /^;base64/.match(@data) + @data = @data[7 .. -1] + end + unless /^,/.match(@data) + raise 'Invalid data URI' + end + @data = @data[1 .. -1] + @data = base64 ? Base64.decode64(@data) : URI.decode(@data) + end + end + + @@schemes['DATA'] = Data + +end diff --git a/test/test_data_open_uri.rb b/test/test_data_open_uri.rb new file mode 100644 index 0000000..d1928a0 --- /dev/null +++ b/test/test_data_open_uri.rb @@ -0,0 +1,36 @@ +require 'data_uri' +require 'open-uri' +require 'data_uri/open_uri' +require 'minitest/autorun' + +describe URI::Data do + + describe "a valid data URI" do + + before do + @base64 = "R0lGODlhAQABAIABAAAAAP///yH5BAEAAAEALAAAAAABAAEAQAICTAEAOw==" + @uri = URI.parse("data:image/gif;base64,#{@base64}") + @data = Base64.decode64(@base64) + end + + it "should open" do + @uri.open.read.must_equal @data + end + + it "should open with a block" do + @uri.open do |io| + io.read.must_equal @data + end + end + + it "should have content_type on opened IO" do + @uri.open.content_type.must_equal 'image/gif' + end + + it "should open on Kernel.open" do + open(@uri).read.must_equal @uri.data + end + + end + +end diff --git a/test/test_data_uri.rb b/test/test_data_uri.rb index c863336..3ceacb1 100644 --- a/test/test_data_uri.rb +++ b/test/test_data_uri.rb @@ -3,7 +3,7 @@ describe URI::Data do - describe "a valid data URI" do + describe "a base64 encoded image/gif data URI" do before do @base64 = "R0lGODlhAQABAIABAAAAAP///yH5BAEAAAEALAAAAAABAAEAQAICTAEAOw==" @@ -18,11 +18,31 @@ @uri.content_type.must_equal 'image/gif' end - it "should have decoded data" do + it "should have data" do require 'base64' @uri.data.must_equal Base64.decode64(@base64) end end + describe "a text/plain data URI" do + + before do + @uri = URI.parse("data:,A%20brief%20note") + end + + it "should parse as a URI::Data object" do + @uri.class.must_equal URI::Data + end + + it "should have a content_type of text/plain" do + @uri.content_type.must_equal 'text/plain' + end + + it "should have data" do + @uri.data.must_equal 'A brief note' + end + + end + end