im_onix 1.0.2 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/.yardopts +1 -0
- data/Gemfile +8 -0
- data/LICENSE.md +7 -0
- data/README.md +3 -3
- data/Rakefile +10 -0
- data/bin/html_codelist_to_yml.rb +14 -15
- data/bin/onix_bench.rb +1 -0
- data/bin/onix_pp.rb +4 -8
- data/bin/onix_serialize.rb +27 -0
- data/doc-src/handlers.rb +154 -0
- data/im_onix.gemspec +32 -0
- data/lib/im_onix.rb +0 -1
- data/lib/onix/addressee.rb +10 -0
- data/lib/onix/code.rb +108 -282
- data/lib/onix/collateral_detail.rb +24 -17
- data/lib/onix/collection.rb +38 -0
- data/lib/onix/collection_sequence.rb +7 -0
- data/lib/onix/contributor.rb +40 -39
- data/lib/onix/date.rb +73 -109
- data/lib/onix/descriptive_detail.rb +90 -417
- data/lib/onix/discount_coded.rb +3 -16
- data/lib/onix/entity.rb +28 -62
- data/lib/onix/epub_usage_constraint.rb +7 -0
- data/lib/onix/epub_usage_limit.rb +6 -0
- data/lib/onix/extent.rb +39 -0
- data/lib/onix/helper.rb +25 -25
- data/lib/onix/identifier.rb +13 -54
- data/lib/onix/language.rb +8 -0
- data/lib/onix/market.rb +5 -0
- data/lib/onix/market_publishing_detail.rb +20 -0
- data/lib/onix/onix21.rb +76 -139
- data/lib/onix/onix_message.rb +87 -100
- data/lib/onix/price.rb +19 -39
- data/lib/onix/product.rb +141 -637
- data/lib/onix/product_form_feature.rb +7 -0
- data/lib/onix/product_part.rb +89 -0
- data/lib/onix/product_supplies_extractor.rb +275 -0
- data/lib/onix/product_supply.rb +17 -58
- data/lib/onix/publishing_detail.rb +16 -32
- data/lib/onix/related_material.rb +4 -3
- data/lib/onix/related_product.rb +9 -29
- data/lib/onix/related_work.rb +3 -17
- data/lib/onix/sales_outlet.rb +2 -10
- data/lib/onix/sales_restriction.rb +8 -21
- data/lib/onix/sales_rights.rb +1 -5
- data/lib/onix/sender.rb +12 -0
- data/lib/onix/serializer.rb +156 -0
- data/lib/onix/subject.rb +9 -30
- data/lib/onix/subset.rb +88 -78
- data/lib/onix/supply_detail.rb +42 -0
- data/lib/onix/supporting_resource.rb +29 -86
- data/lib/onix/tax.rb +9 -18
- data/lib/onix/territory.rb +23 -17
- data/lib/onix/title_detail.rb +22 -0
- data/lib/onix/title_element.rb +32 -0
- data/lib/onix/website.rb +3 -16
- metadata +53 -34
@@ -1,45 +1,41 @@
|
|
1
1
|
module ONIX
|
2
2
|
class TextContent < SubsetDSL
|
3
|
-
element "TextType", :subset
|
3
|
+
element "TextType", :subset, :shortcut => :type
|
4
4
|
element "ContentAudience", :subset
|
5
5
|
element "Text", :text
|
6
6
|
element "TextAuthor", :text
|
7
7
|
element "SourceTitle", :text
|
8
8
|
|
9
|
-
scope :description, lambda { human_code_match(:text_type, "Description")}
|
10
|
-
scope :short_description, lambda { human_code_match(:text_type, "ShortDescriptionannotation")}
|
11
|
-
|
12
|
-
# shortcuts
|
13
|
-
def type
|
14
|
-
@text_type
|
15
|
-
end
|
9
|
+
scope :description, lambda { human_code_match(:text_type, "Description") }
|
10
|
+
scope :short_description, lambda { human_code_match(:text_type, "ShortDescriptionannotation") }
|
16
11
|
end
|
17
12
|
|
18
13
|
class CollateralDetail < SubsetDSL
|
19
14
|
elements "TextContent", :subset
|
20
15
|
elements "SupportingResource", :subset
|
21
16
|
|
17
|
+
# @!group High level
|
18
|
+
|
19
|
+
# product description string including HTML
|
20
|
+
# @return [String]
|
22
21
|
def description
|
23
|
-
desc_contents
|
22
|
+
desc_contents = @text_contents.description + @text_contents.short_description
|
24
23
|
if desc_contents.length > 0
|
25
24
|
desc_contents.first.text
|
26
|
-
else
|
27
|
-
nil
|
28
25
|
end
|
29
26
|
end
|
30
27
|
|
31
|
-
# largest frontcover if multiple
|
32
28
|
def frontcover_resource
|
33
|
-
fc
|
29
|
+
fc = @supporting_resources.front_cover
|
34
30
|
if fc.length > 0
|
35
31
|
if fc.length > 1
|
36
|
-
best_found=fc.select{|c| c.versions.last and c.versions.last.image_width}.sort { |c1, c2| c2.versions.last.image_width <=> c1.versions.last.image_width }.first
|
32
|
+
best_found = fc.select { |c| c.versions.last and c.versions.last.image_width }.sort { |c1, c2| c2.versions.last.image_width <=> c1.versions.last.image_width }.first
|
37
33
|
if best_found
|
38
34
|
# we take larger one
|
39
35
|
best_found.versions.last
|
40
36
|
else
|
41
37
|
# we try first that is not gif
|
42
|
-
fc.select{|sr| not sr.versions.last.file_format=="Gif"}.first.versions.last
|
38
|
+
fc.select { |sr| not sr.versions.last.file_format == "Gif" }.first.versions.last
|
43
39
|
end
|
44
40
|
else
|
45
41
|
fc.first.versions.last
|
@@ -47,18 +43,22 @@ module ONIX
|
|
47
43
|
end
|
48
44
|
end
|
49
45
|
|
46
|
+
# product larger front cover URL string
|
47
|
+
# @return [String]
|
50
48
|
def frontcover_url
|
51
49
|
if self.frontcover_resource
|
52
50
|
self.frontcover_resource.links.first.strip
|
53
51
|
end
|
54
52
|
end
|
55
53
|
|
54
|
+
# product larger front cover last updated date
|
56
55
|
def frontcover_last_updated
|
57
56
|
if self.frontcover_resource
|
58
|
-
|
57
|
+
self.frontcover_resource.last_updated
|
59
58
|
end
|
60
59
|
end
|
61
60
|
|
61
|
+
# product larger front cover mimetype
|
62
62
|
def frontcover_mimetype
|
63
63
|
if self.frontcover_resource
|
64
64
|
self.frontcover_resource.file_mimetype
|
@@ -66,29 +66,36 @@ module ONIX
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def epub_sample_resource
|
69
|
-
es
|
69
|
+
es = @supporting_resources.sample_content.select { |sr| sr.versions.last and sr.versions.last.file_format == "Epub" }.first
|
70
70
|
if es
|
71
71
|
es.versions.last
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
+
# Epub sample URL
|
76
|
+
# @return [String]
|
75
77
|
def epub_sample_url
|
76
78
|
if self.epub_sample_resource
|
77
79
|
self.epub_sample_resource.links.first.strip
|
78
80
|
end
|
79
81
|
end
|
80
82
|
|
83
|
+
# Epub sample last updated
|
84
|
+
# @return [Date]
|
81
85
|
def epub_sample_last_updated
|
82
86
|
if self.epub_sample_resource
|
83
87
|
self.epub_sample_resource.last_updated
|
84
88
|
end
|
85
89
|
end
|
86
90
|
|
91
|
+
# Epub sample mimetype
|
92
|
+
# @return [String]
|
87
93
|
def epub_sample_mimetype
|
88
94
|
if self.epub_sample_resource
|
89
95
|
self.epub_sample_resource.file_mimetype
|
90
96
|
end
|
91
97
|
end
|
92
98
|
|
99
|
+
# @!endgroup
|
93
100
|
end
|
94
101
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module ONIX
|
2
|
+
class Collection < SubsetDSL
|
3
|
+
element "CollectionType", :subset, :shortcut => :type
|
4
|
+
elements "CollectionIdentifier", :subset, :shortcut => :identifiers
|
5
|
+
elements "TitleDetail", :subset
|
6
|
+
elements "CollectionSequence", :subset, :shortcut => :sequences
|
7
|
+
|
8
|
+
scope :publisher, lambda { human_code_match(:collection_type, "PublisherCollection") }
|
9
|
+
|
10
|
+
# @!group High level
|
11
|
+
|
12
|
+
# collection title string
|
13
|
+
def title
|
14
|
+
if collection_title_element
|
15
|
+
collection_title_element.title
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# collection subtitle string
|
20
|
+
def subtitle
|
21
|
+
if collection_title_element
|
22
|
+
collection_title_element.subtitle
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def collection_title_element
|
27
|
+
distinctive_title = @title_details.distinctive_title.first
|
28
|
+
#select { |td| td.type.human=~/DistinctiveTitle/}.first
|
29
|
+
if distinctive_title
|
30
|
+
distinctive_title.title_elements.collection_level.first
|
31
|
+
#select { |te| te.level.human=~/CollectionLevel/ or te.level.human=~/Subcollection/ }.first
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# @!endgroup
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/lib/onix/contributor.rb
CHANGED
@@ -4,72 +4,73 @@ require 'onix/website'
|
|
4
4
|
module ONIX
|
5
5
|
class Contributor < SubsetDSL
|
6
6
|
element "SequenceNumber", :integer
|
7
|
-
element "ContributorRole", :subset
|
8
|
-
elements "NameIdentifier", :subset
|
9
|
-
|
7
|
+
element "ContributorRole", :subset, :shortcut => :role
|
8
|
+
elements "NameIdentifier", :subset, :shortcut => :identifiers
|
10
9
|
element "PersonName", :text
|
11
10
|
element "PersonNameInverted", :text
|
12
|
-
|
13
|
-
element "NamesBeforeKey", :text
|
11
|
+
element "NamesBeforeKey", :text, :shortcut => :name_before_key
|
14
12
|
element "KeyNames", :text
|
15
|
-
|
13
|
+
element "CorporateName", :text
|
14
|
+
element "CorporateNameInverted", :text
|
16
15
|
element "BiographicalNote", :text
|
17
16
|
elements "Website", :subset
|
18
|
-
element "ContributorPlace", :subset
|
19
|
-
|
20
|
-
def role
|
21
|
-
@contributor_role
|
22
|
-
end
|
23
|
-
|
24
|
-
def identifiers
|
25
|
-
@name_identifiers
|
26
|
-
end
|
27
|
-
|
28
|
-
def place
|
29
|
-
@contributor_place
|
30
|
-
end
|
31
|
-
|
32
|
-
def name_before_key
|
33
|
-
@names_before_key
|
34
|
-
end
|
17
|
+
element "ContributorPlace", :subset, :shortcut => :place
|
18
|
+
elements "ContributorDate", :subset, :shortcut => :dates
|
35
19
|
|
36
|
-
#
|
20
|
+
# @!group High level
|
37
21
|
# flatten person name (firstname lastname)
|
22
|
+
# @return [String]
|
38
23
|
def name
|
39
|
-
if @person_name
|
40
|
-
|
41
|
-
|
42
|
-
if @
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
@key_names
|
47
|
-
end
|
24
|
+
return @person_name if @person_name
|
25
|
+
|
26
|
+
if @key_names
|
27
|
+
if @names_before_key
|
28
|
+
return "#{@names_before_key} #{@key_names}"
|
29
|
+
else
|
30
|
+
return @key_names
|
48
31
|
end
|
49
32
|
end
|
33
|
+
|
34
|
+
@corporate_name
|
50
35
|
end
|
51
36
|
|
52
|
-
# :category: High level
|
53
37
|
# inverted flatten person name
|
38
|
+
# @return [String]
|
54
39
|
def inverted_name
|
55
|
-
@person_name_inverted
|
40
|
+
@person_name_inverted || @corporate_name_inverted
|
56
41
|
end
|
57
42
|
|
58
|
-
# :category: High level
|
59
43
|
# biography string with HTML
|
44
|
+
# @return [String]
|
60
45
|
def biography
|
61
46
|
@biographical_note
|
62
47
|
end
|
63
48
|
|
64
|
-
# :category: High level
|
65
49
|
# raw biography string without HTML
|
50
|
+
# @return [String]
|
66
51
|
def raw_biography
|
67
52
|
if self.biography
|
68
53
|
Helper.strip_html(self.biography).gsub(/\s+/, " ")
|
69
|
-
else
|
70
|
-
nil
|
71
54
|
end
|
72
55
|
end
|
56
|
+
|
57
|
+
# date of birth
|
58
|
+
# @return [Time]
|
59
|
+
def birth_date
|
60
|
+
if contributor_date = @contributor_dates.find { |d| d.role.human == "DateOfBirth" }
|
61
|
+
contributor_date.date.to_time
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# date of death
|
66
|
+
# @return [Time]
|
67
|
+
def death_date
|
68
|
+
if contributor_date = @contributor_dates.find { |d| d.role.human == "DateOfDeath" }
|
69
|
+
contributor_date.date.to_time
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# @!endgroup
|
73
74
|
end
|
74
75
|
|
75
76
|
class ContributorPlace < SubsetDSL
|
data/lib/onix/date.rb
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
module ONIX
|
2
|
-
|
3
2
|
module DateHelper
|
4
3
|
attr_accessor :date_format, :date
|
5
4
|
|
6
5
|
def parse_date(n)
|
7
|
-
@date_format=DateFormat.from_code("00")
|
8
|
-
date_txt=nil
|
9
|
-
@date=nil
|
6
|
+
@date_format = DateFormat.from_code("00")
|
7
|
+
date_txt = nil
|
8
|
+
@date = nil
|
10
9
|
n.elements.each do |t|
|
11
10
|
case t
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
when tag_match("DateFormat")
|
12
|
+
@date_format = DateFormat.parse(t)
|
13
|
+
when tag_match("Date")
|
14
|
+
date_txt = t.text
|
16
15
|
end
|
17
16
|
|
18
17
|
if t["dateformat"]
|
@@ -20,29 +19,29 @@ module ONIX
|
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
23
|
-
code_format=format_from_code(@date_format.code)
|
24
|
-
text_format=format_from_string(date_txt)
|
22
|
+
code_format = format_from_code(@date_format.code)
|
23
|
+
text_format = format_from_string(date_txt)
|
25
24
|
|
26
|
-
format=code_format
|
25
|
+
format = code_format
|
27
26
|
|
28
|
-
if code_format!=text_format
|
29
|
-
# puts "EEE date #{n.text} (#{text_format}) do not match code #{@format.code} (#{code_format})"
|
30
|
-
format=text_format
|
27
|
+
if code_format != text_format
|
28
|
+
# puts "EEE date #{n.text} (#{text_format}) do not match code #{@format.code} (#{code_format})"
|
29
|
+
format = text_format
|
31
30
|
end
|
32
31
|
|
33
32
|
begin
|
34
33
|
if format
|
35
34
|
case @date_format.code
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
35
|
+
when "00"
|
36
|
+
@date = Date.strptime(date_txt, format)
|
37
|
+
when "01"
|
38
|
+
@date = Date.strptime(date_txt, format)
|
39
|
+
when "05"
|
40
|
+
@date = Date.strptime(date_txt, format)
|
41
|
+
when "14"
|
42
|
+
@date = Time.strptime(date_txt, format)
|
43
|
+
else
|
44
|
+
@date = nil
|
46
45
|
end
|
47
46
|
end
|
48
47
|
rescue
|
@@ -52,33 +51,33 @@ module ONIX
|
|
52
51
|
|
53
52
|
def format_from_code(code)
|
54
53
|
case code
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
54
|
+
when "00"
|
55
|
+
"%Y%m%d"
|
56
|
+
when "01"
|
57
|
+
"%Y%m"
|
58
|
+
when "05"
|
59
|
+
"%Y"
|
60
|
+
when "14"
|
61
|
+
"%Y%m%dT%H%M%S%z"
|
62
|
+
else
|
63
|
+
nil
|
65
64
|
end
|
66
65
|
end
|
67
66
|
|
68
67
|
def format_from_string(str)
|
69
68
|
case str
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
69
|
+
when /^\d{4}\d{2}\d{2}T\d{2}\d{2}\d{2}/
|
70
|
+
"%Y%m%dT%H%M%S%z"
|
71
|
+
when /^\d{4}\-\d{2}\-\d{2}$/
|
72
|
+
"%Y-%m-%d"
|
73
|
+
when /^\d{4}\d{2}\d{2}$/
|
74
|
+
"%Y%m%d"
|
75
|
+
when /^\d{4}\d{2}$/
|
76
|
+
"%Y%m"
|
77
|
+
when /^\d{4}$/
|
78
|
+
"%Y"
|
79
|
+
else
|
80
|
+
nil
|
82
81
|
end
|
83
82
|
end
|
84
83
|
|
@@ -87,17 +86,8 @@ module ONIX
|
|
87
86
|
end
|
88
87
|
end
|
89
88
|
|
90
|
-
class
|
89
|
+
class BaseDate < SubsetDSL
|
91
90
|
include DateHelper
|
92
|
-
element "Date", :ignore
|
93
|
-
element "DateFormat", :ignore
|
94
|
-
element "MarketDateRole", :subset
|
95
|
-
|
96
|
-
scope :availability, lambda { human_code_match(:market_date_role, ["PublicationDate","EmbargoDate"])}
|
97
|
-
|
98
|
-
def role
|
99
|
-
@market_date_role
|
100
|
-
end
|
101
91
|
|
102
92
|
def parse(n)
|
103
93
|
super
|
@@ -105,79 +95,53 @@ module ONIX
|
|
105
95
|
end
|
106
96
|
end
|
107
97
|
|
108
|
-
class
|
109
|
-
include DateHelper
|
98
|
+
class MarketDate < BaseDate
|
110
99
|
element "Date", :ignore
|
111
100
|
element "DateFormat", :ignore
|
112
|
-
element "
|
113
|
-
|
114
|
-
scope :from_date, lambda { human_code_match(:price_date_role, "FromDate")}
|
115
|
-
scope :until_date, lambda { human_code_match(:price_date_role, "UntilDate")}
|
101
|
+
element "MarketDateRole", :subset, :shortcut => :role
|
116
102
|
|
117
|
-
|
118
|
-
@price_date_role
|
119
|
-
end
|
120
|
-
|
121
|
-
def parse(n)
|
122
|
-
super
|
123
|
-
parse_date(n)
|
124
|
-
end
|
103
|
+
scope :availability, lambda { human_code_match(:market_date_role, ["PublicationDate", "EmbargoDate"]) }
|
125
104
|
end
|
126
105
|
|
127
|
-
class
|
128
|
-
include DateHelper
|
106
|
+
class PriceDate < BaseDate
|
129
107
|
element "Date", :ignore
|
130
108
|
element "DateFormat", :ignore
|
131
|
-
element "
|
132
|
-
|
133
|
-
scope :availability, lambda { human_code_match(:supply_date_role, ["ExpectedAvailabilityDate","EmbargoDate"])}
|
109
|
+
element "PriceDateRole", :subset, :shortcut => :role
|
134
110
|
|
135
|
-
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
def parse(n)
|
140
|
-
super
|
141
|
-
parse_date(n)
|
142
|
-
end
|
111
|
+
scope :from_date, lambda { human_code_match(:price_date_role, "FromDate") }
|
112
|
+
scope :until_date, lambda { human_code_match(:price_date_role, "UntilDate") }
|
143
113
|
end
|
144
114
|
|
145
|
-
class
|
146
|
-
include DateHelper
|
115
|
+
class SupplyDate < BaseDate
|
147
116
|
element "Date", :ignore
|
148
117
|
element "DateFormat", :ignore
|
149
|
-
element "
|
118
|
+
element "SupplyDateRole", :subset, :shortcut => :role
|
150
119
|
|
151
|
-
scope :
|
152
|
-
|
153
|
-
scope :preorder_embargo, lambda { human_code_match(:publishing_date_role, "PreorderEmbargoDate")}
|
154
|
-
scope :public_announcement, lambda { human_code_match(:publishing_date_role, "PublicAnnouncementDate")}
|
120
|
+
scope :availability, lambda { human_code_match(:supply_date_role, ["ExpectedAvailabilityDate", "EmbargoDate"]) }
|
121
|
+
end
|
155
122
|
|
156
|
-
|
157
|
-
|
158
|
-
|
123
|
+
class PublishingDate < BaseDate
|
124
|
+
element "Date", :ignore
|
125
|
+
element "DateFormat", :ignore
|
126
|
+
element "PublishingDateRole", :subset, :shortcut => :role
|
159
127
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
128
|
+
scope :publication, lambda { human_code_match(:publishing_date_role, ["PublicationDate", "PublicationDateOfPrintCounterpart"]) }
|
129
|
+
scope :embargo, lambda { human_code_match(:publishing_date_role, "EmbargoDate") }
|
130
|
+
scope :preorder_embargo, lambda { human_code_match(:publishing_date_role, "PreorderEmbargoDate") }
|
131
|
+
scope :public_announcement, lambda { human_code_match(:publishing_date_role, "PublicAnnouncementDate") }
|
164
132
|
end
|
165
133
|
|
166
|
-
class ContentDate <
|
167
|
-
include DateHelper
|
134
|
+
class ContentDate < BaseDate
|
168
135
|
element "Date", :ignore
|
169
136
|
element "DateFormat", :ignore
|
170
|
-
element "ContentDateRole", :subset
|
171
|
-
|
172
|
-
scope :last_updated, lambda { human_code_match(:content_date_role, "LastUpdated")}
|
137
|
+
element "ContentDateRole", :subset, :shortcut => :role
|
173
138
|
|
174
|
-
|
175
|
-
|
176
|
-
end
|
139
|
+
scope :last_updated, lambda { human_code_match(:content_date_role, "LastUpdated") }
|
140
|
+
end
|
177
141
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
142
|
+
class ContributorDate < BaseDate
|
143
|
+
element "Date", :ignore
|
144
|
+
element "DateFormat", :ignore
|
145
|
+
element "ContributorDateRole", :subset, :shortcut => :role
|
182
146
|
end
|
183
147
|
end
|