From 66955757626b9ca8c1b79288e557cc0f9410ee28 Mon Sep 17 00:00:00 2001 From: John Bintz Date: Tue, 15 Mar 2011 10:55:09 -0400 Subject: [PATCH] more work on image reads --- .autotest | 5 ++ .rspec | 1 - lib/avm/image.rb | 72 ++++++++++++++++--- lib/avm/image_quality.rb | 14 ++++ lib/avm/image_type.rb | 14 ++++ lib/avm/xmp.rb | 26 +++++-- spec/avm/image_spec.rb | 96 ++++++++++++++++++++----- spec/avm/xmp_spec.rb | 23 ++++-- spec/sample_files/image/light_years.xmp | 37 ++++++++++ spec/sample_files/image/nothing.xmp | 18 +++++ 10 files changed, 263 insertions(+), 43 deletions(-) create mode 100644 .autotest create mode 100644 lib/avm/image_quality.rb create mode 100644 lib/avm/image_type.rb create mode 100644 spec/sample_files/image/light_years.xmp create mode 100644 spec/sample_files/image/nothing.xmp diff --git a/.autotest b/.autotest new file mode 100644 index 0000000..2ab7329 --- /dev/null +++ b/.autotest @@ -0,0 +1,5 @@ +Autotest.add_hook :initialize do |at| + at.add_mapping(%r{^spec/sample_files/([^/]+)/.*}, true) { |_, m| + "spec/avm/#{m[1]}_spec.rb" + } +end diff --git a/.rspec b/.rspec index ae67f9d..db400bf 100644 --- a/.rspec +++ b/.rspec @@ -3,4 +3,3 @@ --format progress --format RSpec::Core::Formatters::QuickFixFormatter --out .quickfix.txt - diff --git a/lib/avm/image.rb b/lib/avm/image.rb index dc2e45b..e8effa2 100644 --- a/lib/avm/image.rb +++ b/lib/avm/image.rb @@ -1,8 +1,13 @@ require 'avm/creator' require 'avm/xmp' +require 'avm/image_type' +require 'avm/image_quality' module AVM class Image + DUBLIN_CORE_FIELDS = [ :title, :description ] + AVM_SINGLE_FIELDS = [ 'Distance.Notes', 'ReferenceURL', 'Credit', 'Date', 'ID', 'Type', 'Image.ProductQuality' ] + attr_reader :creator def initialize(options = {}) @@ -16,20 +21,25 @@ module AVM creator.add_to_document(document) document.get_refs do |refs| - [ :title, :description ].each do |field| + DUBLIN_CORE_FIELDS.each do |field| refs[:dublin_core].add_child(%{#{alt_li_tag(send(field))}}) end refs[:photoshop].add_child(%{#{headline}}) - { - 'Distance.Notes' => distance_notes, - 'ReferenceURL' => reference_url, - 'Credit' => credit, - 'Date' => string_date, - 'ID' => id, - }.each do |tag, value| - refs[:avm].add_child(%{#{value}}) if value + AVM_SINGLE_FIELDS.zip([distance_notes, reference_url, credit, string_date, id, image_type, image_quality]).each do |tag, value| + refs[:avm].add_child(%{#{value.to_s}}) if value + end + + distance_nodes = [] + distance_nodes << rdf_li(light_years) if light_years + if redshift + distance_nodes << rdf_li('-') if distance_nodes.empty? + distance_nodes << rdf_li(redshift) + end + + if !distance_nodes.empty? + refs[:avm].add_child(%{#{distance_nodes.join}}) end end @@ -41,7 +51,11 @@ module AVM end def image_type - @options[:type] + (AVM::ImageType.const_get(@options[:type].to_sym).new rescue nil) + end + + def image_quality + (AVM::ImageQuality.const_get(@options[:quality].to_sym).new rescue nil) end def date @@ -60,7 +74,39 @@ module AVM def self.from_xml(string) document = AVM::XMP.from_string(string) - image = new + options = {} + + document.get_refs do |refs| + DUBLIN_CORE_FIELDS.each do |field| + if node = refs[:dublin_core].at_xpath(".//dc:#{field}//rdf:li[1]") + options[field] = node.text + end + end + + AVM_SINGLE_FIELDS.zip([ :distance_notes, :reference_url, :credit, :date, :id, :type, :quality ]).each do |tag, field| + if node = refs[:avm].at_xpath("./avm:#{tag}") + options[field] = node.text + end + end + + if node = refs[:photoshop].at_xpath('./photoshop:Headline') + options[:headline] = node.text + end + + if node = refs[:avm].at_xpath('./avm:Distance') + list_values = node.search('.//ref:li').collect { |li| li.text } + + case list_values.length + when 1 + options[:light_years] = list_values.first + when 2 + options[:light_years] = (list_values.first == '-') ? nil : list_values.first + options[:redshift] = list_valueslast + end + end + end + + image = new(options) image.creator.from_xml(self, document) image end @@ -73,6 +119,10 @@ module AVM def alt_li_tag(text) %{#{text}} end + + def rdf_li(text) + %{#{text}} + end end end diff --git a/lib/avm/image_quality.rb b/lib/avm/image_quality.rb new file mode 100644 index 0000000..ca1a7d9 --- /dev/null +++ b/lib/avm/image_quality.rb @@ -0,0 +1,14 @@ +module AVM + module ImageQuality + %w{Good Moderate Poor}.each do |type| + klass = Class.new do + def to_s + self.class.to_s.split('::').last + end + end + + AVM::ImageQuality.const_set(type.to_sym, klass) + end + end +end + diff --git a/lib/avm/image_type.rb b/lib/avm/image_type.rb new file mode 100644 index 0000000..5c6725c --- /dev/null +++ b/lib/avm/image_type.rb @@ -0,0 +1,14 @@ +module AVM + module ImageType + %w{Observation Artwork Photographic Planetary Simulation Chart Collage}.each do |type| + klass = Class.new do + def to_s + self.class.to_s.split('::').last + end + end + + AVM::ImageType.const_set(type.to_sym, klass) + end + end +end + diff --git a/lib/avm/xmp.rb b/lib/avm/xmp.rb index cc1ed09..e9bc4c4 100644 --- a/lib/avm/xmp.rb +++ b/lib/avm/xmp.rb @@ -5,7 +5,8 @@ module AVM PREFIXES = { 'dc' => 'Dublin Core', 'Iptc4xmpCore' => 'IPTC', - 'Photoshop' => 'Photoshop' + 'photoshop' => 'Photoshop', + 'avm' => 'AVM' } attr_reader :doc @@ -39,13 +40,24 @@ module AVM end def ensure_descriptions_findable! + added = [] + doc.search('//rdf:Description').each do |description| if first_child = description.first_element_child if first_child.namespace - description['about'] = PREFIXES[first_child.namespace.prefix] + prefix = first_child.namespace.prefix + + description['rdf:about'] = PREFIXES[prefix] + added << prefix end end end + + PREFIXES.each do |prefix, about| + if !added.include?(prefix) + doc.at_xpath('//rdf:RDF').add_child(%{}) + end + end end def dublin_core @@ -65,17 +77,17 @@ module AVM end def at_rdf_description(about) - @doc.at_xpath(%{//rdf:Description[@about="#{about}"]}) + @doc.at_xpath(%{//rdf:Description[@rdf:about="#{about}"]}) end def empty_xml_doc Nokogiri::XML(<<-XML) - - - - + + + + XML diff --git a/spec/avm/image_spec.rb b/spec/avm/image_spec.rb index 905cc42..892930a 100644 --- a/spec/avm/image_spec.rb +++ b/spec/avm/image_spec.rb @@ -15,7 +15,7 @@ describe AVM::Image do let(:credit) { 'Credit' } let(:date) { '2010-01-01' } let(:id) { 'ID' } - let(:type) { 'Obvservation' } + let(:type) { 'Observation' } let(:image_quality) { 'Good' } let(:redshift) { 'Redshift' } let(:light_years) { 'Light years' } @@ -31,17 +31,13 @@ describe AVM::Image do :date => date, :id => id, :type => type, - :image_quality => image_quality, + :quality => image_quality, :redshift => redshift, :light_years => light_years } } end - describe '#initialize' do - with_all_options - - it { should be_a_kind_of(AVM::Image) } - + def self.has_most_options its(:creator) { should be_a_kind_of(AVM::Creator) } its(:title) { should == title } its(:headline) { should == headline } @@ -51,20 +47,74 @@ describe AVM::Image do its(:credit) { should == credit } its(:date) { should == Time.parse(date) } its(:id) { should == id } - its(:image_type) { should == type } - its(:image_quality) { should == image_quality } - its(:redshift) { should == redshift } - its(:light_years) { should == light_years } + its(:image_type) { should be_a_kind_of eval("AVM::ImageType::#{type}") } + its(:image_quality) { should be_a_kind_of eval("AVM::ImageQuality::#{image_quality}") } + end + + describe '#initialize' do + with_all_options + + it { should be_a_kind_of(AVM::Image) } + + has_most_options its(:distance) { should == [ light_years, redshift ] } end + describe '.from_xml' do + let(:image) { AVM::Image.from_xml(File.read(file_path)) } + + subject { image } + + context "nothing in it" do + let(:file_path) { 'spec/sample_files/image/nothing.xmp' } + + its(:title) { should be_nil } + its(:headline) { should be_nil } + its(:description) { should be_nil } + its(:distance_notes) { should be_nil } + its(:reference_url) { should be_nil } + its(:credit) { should be_nil } + its(:date) { should be_nil } + its(:id) { should be_nil } + its(:image_type) { should be_nil } + its(:image_quality) { should be_nil } + its(:redshift) { should be_nil } + its(:light_years) { should be_nil } + end + + context "image in it" do + context "distance in light years" do + let(:file_path) { 'spec/sample_files/image/light_years.xmp' } + + has_most_options + + its(:redshift) { should be_nil } + end + + context "distaince in redshift" do + + let(:file_path) { 'spec/sample_files/image/redshift.xmp' } + end + context "distance in both" do + + let(:file_path) { 'spec/sample_files/image/both.xmp' } + + end + context "distance in neither" do + + let(:file_path) { 'spec/sample_files/image/neither.xmp' } + end + end + + end + describe '#to_xml' do let(:xml) { image.to_xml } - let(:dublin_core) { xml.at_xpath('//rdf:Description[@about="Dublin Core"]') } - let(:photoshop) { xml.at_xpath('//rdf:Description[@about="Photoshop"]') } - let(:avm) { xml.at_xpath('//rdf:Description[@about="AVM"]') } + let(:dublin_core) { xml.at_xpath('//rdf:Description[@rdf:about="Dublin Core"]') } + let(:photoshop) { xml.at_xpath('//rdf:Description[@rdf:about="Photoshop"]') } + let(:avm) { xml.at_xpath('//rdf:Description[@rdf:about="AVM"]') } context 'nothing in it' do it "should have basic tags" do @@ -87,23 +137,35 @@ describe AVM::Image do avm.at_xpath('./avm:Credit').text.should == credit avm.at_xpath('./avm:Date').text.should == date avm.at_xpath('./avm:ID').text.should == id + avm.at_xpath('./avm:Type').text.should == type + avm.at_xpath('./avm:Image.ProductQuality').text.should == image_quality end context "distance" do context "no distances" do + let(:redshift) { nil } + let(:light_years) { nil } + specify { avm.at_xpath('./avm:Distance').should be_nil } end context "redshift only" do - + let(:light_years) { nil } + + specify { avm.at_xpath('./avm:Distance/rdf:Seq/rdf:li[1]').text.should == '-' } + specify { avm.at_xpath('./avm:Distance/rdf:Seq/rdf:li[2]').text.should == redshift } end context "light years only" do - + let(:redshift) { nil } + + specify { avm.at_xpath('./avm:Distance/rdf:Seq/rdf:li[1]').text.should == light_years } + specify { avm.at_xpath('./avm:Distance/rdf:Seq/rdf:li[2]').should be_nil } end context "redshift and light years" do - + specify { avm.at_xpath('./avm:Distance/rdf:Seq/rdf:li[1]').text.should == light_years } + specify { avm.at_xpath('./avm:Distance/rdf:Seq/rdf:li[2]').text.should == redshift } end end end diff --git a/spec/avm/xmp_spec.rb b/spec/avm/xmp_spec.rb index b0834e0..d2c30f3 100644 --- a/spec/avm/xmp_spec.rb +++ b/spec/avm/xmp_spec.rb @@ -12,18 +12,21 @@ describe AVM::XMP do refs[:dublin_core] << "" refs[:iptc] << "" refs[:photoshop] << '' + refs[:avm] << '' end } it "should have gotten the refs correctly" do - xmp.doc.at_xpath('//rdf:Description[@about="Dublin Core"]//rdf:addedToDublinCore').should_not be_nil - xmp.doc.at_xpath('//rdf:Description[@about="IPTC"]//rdf:addedToIPTC').should_not be_nil + xmp.doc.at_xpath('//rdf:Description[@rdf:about="Dublin Core"]//rdf:addedToDublinCore').should_not be_nil + xmp.doc.at_xpath('//rdf:Description[@rdf:about="IPTC"]//rdf:addedToIPTC').should_not be_nil + xmp.doc.at_xpath('//rdf:Description[@rdf:about="Photoshop"]//rdf:addedToPhotoshop').should_not be_nil + xmp.doc.at_xpath('//rdf:Description[@rdf:about="AVM"]//rdf:addedToAVM').should_not be_nil end end describe '.from_string' do let(:xmp) { self.class.describes.from_string(string) } - let(:string) { '' } + let(:string) { '' } specify { xmp.doc.at_xpath('//node').should_not be_nil } end @@ -42,8 +45,8 @@ describe AVM::XMP do context 'no nodes within' do let(:content) { '' } - [ 'Dublin Core', 'IPTC' ].each do |which| - specify { xmp.doc.at_xpath(%{//rdf:Description[@about="#{which}"]}).should be_nil } + [ 'Dublin Core', 'IPTC', 'Photoshop', 'AVM' ].each do |which| + specify { xmp.doc.at_xpath(%{//rdf:Description[@rdf:about="#{which}"]}).children.should be_empty } end end @@ -54,11 +57,17 @@ describe AVM::XMP do + + + + + + XML - [ 'Dublin Core', 'IPTC' ].each do |which| - specify { xmp.doc.at_xpath(%{//rdf:Description[@about="#{which}"]}).should_not be_nil } + [ 'Dublin Core', 'IPTC', 'Photoshop', 'AVM' ].each do |which| + specify { xmp.doc.at_xpath(%{//rdf:Description[@rdf:about="#{which}"]}).should_not be_nil } end end end diff --git a/spec/sample_files/image/light_years.xmp b/spec/sample_files/image/light_years.xmp new file mode 100644 index 0000000..b32eb55 --- /dev/null +++ b/spec/sample_files/image/light_years.xmp @@ -0,0 +1,37 @@ + + + + : + + My title + + + + + Description + + + + + + + + + + Headline + + + Distance Notes + Reference URL + Credit + 2010-01-01 + ID + Observation + Good + + + diff --git a/spec/sample_files/image/nothing.xmp b/spec/sample_files/image/nothing.xmp new file mode 100644 index 0000000..10120de --- /dev/null +++ b/spec/sample_files/image/nothing.xmp @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + +