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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+