Skip to content

Instantly share code, notes, and snippets.

@mwlang
Created April 22, 2015 23:37
Show Gist options
  • Save mwlang/58637144c7bf032c7205 to your computer and use it in GitHub Desktop.
Save mwlang/58637144c7bf032c7205 to your computer and use it in GitHub Desktop.
module Onix21
class Base
include Logger
attr_reader :values
attr_reader :properties
def section_matches_class section
self_class = self.class.to_s.underscore.split('/').last.gsub("_",'').to_sym
raise "#{self_class.inspect} expected, but got #{section.inspect}" unless self_class == section
end
def initialize section, values, parent = nil
section_matches_class section
@properties = []
@values = values.first.is_a?(Array) ? values : [values]
assign_properties
unless fully_consumed?
puts '=' * 40
puts section.inspect
pp @values
puts "Belongs to: #{parent.class.name}" if parent
puts '-' * 40
end
end
def extract_items xml_tag
(extracted, @values = @values.partition{|p| p[0] == xml_tag}).first
end
def extract section, parent = nil
xml_tag = section.to_s.gsub("_", '').to_sym
klass = "Onix21::#{section.to_s.camelize}".constantize
extract_items(xml_tag).map{ |values| klass.new(*values, parent) }
end
def set_if_present property_name, xml_tag, present_value
extracted = extract_items xml_tag
instance_variable_set "@#{property_name}", (extracted.empty? ? !present_value : present_value)
end
def extract_property property_name, xml_tag, repeatable = false
limit = (!!repeatable ? 999 : 1)
extracted = extract_items xml_tag
if extracted.size > limit
raise "set_property expects only one instance for #{property_name}/#{xml_tag}, but got #{extracted.size}"
end
return Array(extracted.first).last
end
def set_property property_name, xml_tag, repeatable = false
value = extract_property(property_name, xml_tag, repeatable)
instance_variable_set "@#{property_name}", value
end
# Can set date from any of YYYY, YYYYMM, or YYYYMMDD
def set_property_date property_name, xml_tag
value = extract_property(property_name, xml_tag, false)
if value and matches = value.match(/(\d{4})(\d{2})?(\d{2})?/)
instance_variable_set "@#{property_name}", Date.new(*matches.captures.compact.map(&:to_i))
else
instance_variable_set "@#{property_name}", nil
end
end
def set_property_list property_name, xml_tag, repeatable = false
value = extract_property(property_name, xml_tag, repeatable)
instance_variable_set "@#{property_name}", value.nil? ? nil : value.split(" ")
end
def fully_consumed?
values.empty?
end
end
end
module Onix21
class Product < Base
attr_reader :values
attr_reader :main_subject, :subjects, :identifiers, :contributors, :supply_details
attr_reader :series, :sales_rights, :measures, :work_identifiers
attr_reader :publishers, :product_websites, :audience_ranges
attr_reader :imprints, :related_products, :titles
attr_reader :contained_items, :sets, :extents
attr_reader :bwk_rec_ref_num, :other_texts
attr_reader :notification_type, :record_source_type, :record_source_name
attr_reader :barcodes, :product_form, :product_form_details, :product_packaging
attr_reader :epub_type, :epub_type_description, :epub_type_note, :epub_format, :epub_source, :epub_source_description
attr_reader :number_of_pages, :number_of_illustrations, :pages_roman, :pages_arabic
attr_reader :bisac_main_subject_category, :bisac_version
attr_reader :audience_codes
attr_reader :city_of_publication, :country_of_publication
attr_reader :publication_date, :copyright_year, :year_first_published, :out_of_print_date
attr_reader :edition_type_codes, :edition_number
attr_reader :publishing_status_code
attr_reader :illustrations_note
attr_reader :no_contributor
attr_reader :no_series
attr_reader :trade_category
attr_reader :number_of_volumes
attr_reader :languages
attr_reader :distinctive_title, :title_prefix, :title_without_prefix, :sub_title
attr_reader :title_text_case, :translated_title, :former_title
def id
@id ||= (item = @identifiers.detect{|d| d.type == '03'} and item.id)
end
def isbn
@isbn ||= (item = @identifiers.detect{|d| d.type == '02'} and item.id)
end
def publisher_record
@publisher_record ||= publishers.first.record rescue nil
end
def publisher_id
publisher_record and publisher_record[:id]
end
def imprint_record
@imprint_record ||= imprints.first.record rescue nil
end
def imprint_id
return imprint_record[:id] if imprint_record
return publisher_record[:id] if publisher_record
end
def imprint_name
return imprint_record[:name] if imprint_record
return publisher_record[:name] if publisher_record
end
def description
if other_text = other_texts.detect{|d| d.type == '01'}
other_text.description
else
''
end
end
def title_parts
if product_title = titles.detect{|d| d.type == '01'}
product_title.title_parts
else
raise ImportError, "Title not found for type '01'"
end
end
def get_avail_status_id(avail_status_code)
raise ImportError, "No avail_status_code given!" if avail_status_code.blank?
db[:avail_statuses].filter(code: avail_status_code).get(:id)
end
def get_avail_status_code
unless publishing_status_code.blank?
code = db[:avail_statuses___av].
join(:publishing_statuses___ps, :ps__avail_status_id => :av__id).
filter(ps__code: publishing_status_code).
get(:av__code)
return code unless code.blank?
end
return product_availability_code unless product_availability_code.blank?
unless fallback_availability_status_code.blank?
code = db[:avail_statuses___av].
join(:product_avail_statuses___pas, :pas__avail_status_id => :av__id).
filter(pas__code: fallback_availability_status_code).
get(:av__code)
return code unless code.blank?
end
raise ImportError, "Could not look up avail_status_code"
end
def product_availability_code
(sd = supply_details.first) ? sd.product_availability_code : nil
end
def fallback_availability_status_code
(sd = supply_details.first) ? sd.availability_status_code : nil
end
def availability_status_code
@avail_status_code ||= get_avail_status_code(fallback_avail_status)
end
def availability_status_id
@avail_status_id ||= get_avail_status_id(availability_status_code)
end
# supply_to_country and supply_to_territory supplies detailed regional availability,
# however, Polybook only cares about "US" and "GB" where Bowker data is concerned,
# so we base market_code off the Bowker UID for the product and ignore the territorial data
def market_code
return "US" if bwk_rec_ref_num =~ /USA/
return "GB"
end
def replaced_by_product
@replaced ||= related_products.detect{|p| p.type == '05'}
end
def replaces_product
@replaces ||= related_products.detect{|p| p.type == '03'}
end
def replaced_by_item_id
replaced_by_product ? replaced_by_product.id : nil
end
def replaces_item_id
replaces_product ? replaces_product.id : nil
end
# NOTE: the leading comma is intentional (as taken from original Perl script).
def pagination
[pages_roman.to_s, (pages_arabic || number_of_pages).to_s].join(", ")
end
def get_measure type
@measures.detect{|d| d.type == type}
end
def weight
(measure = get_measure("08")) ? measure.convert_to_grams : nil
end
def dimensions_length
(measure = get_measure("01")) ? measure.convert_to_cm : nil
end
def dimensions_width
(measure = get_measure("02")) ? measure.convert_to_cm : nil
end
def dimensions_height
(measure = get_measure("03")) ? measure.convert_to_cm : nil
end
def website_urls
product_websites.map(&:short_url).join(";")
end
def publication_language
(lang = @languages.detect{|l| l.role == '01'}) ? lang.code : nil
end
def original_language
(lang = @languages.detect{|l| l.role == '02'}) ? lang.code : nil
end
def all_subjects
@all_subjects = main_subject + subjects
end
def dewey
@dewey ||= (subj = all_subjects.detect{|s| s.scheme_id == '01'}) ? subj.value : nil
end
def lc_class
@lc_class ||= (subj = all_subjects.detect{|s| s.scheme_id == '03'}) ? subj.value : nil
end
def work_id
(ident = @worker_identifiers.detect{|w| w.type == '01'}) ? ident.id : nil
end
def assign_properties
@main_subject = extract(:main_subject)
@subjects = extract(:subject)
@identifiers = extract(:product_identifier)
@contributors = extract(:contributor)
@supply_details = extract(:supply_detail)
@series = extract(:series)
@other_texts = Array(extract(:other_text))
@sales_rights = extract(:sales_rights)
@measures = extract(:measure)
@work_identifiers = extract(:work_identifier)
@publishers = extract(:publisher)
@titles = extract(:title)
@languages = extract(:language)
@product_websites = extract(:product_website)
@audience_ranges = extract(:audience_range)
@imprints = extract(:imprint)
@related_products = extract(:related_product)
@prizes = extract(:prize)
@contained_items = extract(:contained_item)
@sets = extract(:set)
@extents = extract(:extent)
set_property :bwk_rec_ref_num, :a001
set_property :notification_type, :a002
set_property :record_source_type, :a194
set_property :record_source_name, :a197
set_property :barcode, :b246, :repeatable
set_property :product_form, :b012
set_property :product_form_details, :b333, :repeatable
set_property :product_packaging, :b225
set_property :epub_type, :b211
set_property :epub_type_description, :b213
set_property :epub_type_note, :b277
set_property :epub_format, :b214
set_property :epub_source, :b278
set_property :epub_source_description, :b280
set_property :number_of_pages, :b061
set_property :pages_roman, :b254
set_property :pages_arabic, :b255
set_property :bisac_main_subject_category, :b064
set_property :bisac_version, :b200
set_property :audience_codes, :b073, :repeatable
set_property :city_of_publication, :b209
set_property :country_of_publication, :b083
set_property_date :publication_date, :b003
set_property_date :out_of_print_date, :h134
set_property :copyright_year, :b087
set_property :edition_type_codes, :b056, :repeatable
set_property :publishing_status_code, :b394
set_property :number_of_illustrations, :b125
set_property :illustrations_note, :b062
set_property :edition_number, :b057
set_property :year_first_published, :b088
set_if_present :no_contributor, :n339, true
set_if_present :no_series, :n338, true
set_property :trade_category, :b384
set_property :number_of_volumes, :b210
set_property :distinctive_title, :b028
set_property :title_prefix, :b030
set_property :title_without_prefix, :b031
set_property :sub_title, :b029
set_property :title_text_case, :b027
set_property :translated_title, :b032
set_property :former_title, :b033
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment