im_onix 1.0.2 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.yardopts +1 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE.md +7 -0
  6. data/README.md +3 -3
  7. data/Rakefile +10 -0
  8. data/bin/html_codelist_to_yml.rb +14 -15
  9. data/bin/onix_bench.rb +1 -0
  10. data/bin/onix_pp.rb +4 -8
  11. data/bin/onix_serialize.rb +27 -0
  12. data/doc-src/handlers.rb +154 -0
  13. data/im_onix.gemspec +32 -0
  14. data/lib/im_onix.rb +0 -1
  15. data/lib/onix/addressee.rb +10 -0
  16. data/lib/onix/code.rb +108 -282
  17. data/lib/onix/collateral_detail.rb +24 -17
  18. data/lib/onix/collection.rb +38 -0
  19. data/lib/onix/collection_sequence.rb +7 -0
  20. data/lib/onix/contributor.rb +40 -39
  21. data/lib/onix/date.rb +73 -109
  22. data/lib/onix/descriptive_detail.rb +90 -417
  23. data/lib/onix/discount_coded.rb +3 -16
  24. data/lib/onix/entity.rb +28 -62
  25. data/lib/onix/epub_usage_constraint.rb +7 -0
  26. data/lib/onix/epub_usage_limit.rb +6 -0
  27. data/lib/onix/extent.rb +39 -0
  28. data/lib/onix/helper.rb +25 -25
  29. data/lib/onix/identifier.rb +13 -54
  30. data/lib/onix/language.rb +8 -0
  31. data/lib/onix/market.rb +5 -0
  32. data/lib/onix/market_publishing_detail.rb +20 -0
  33. data/lib/onix/onix21.rb +76 -139
  34. data/lib/onix/onix_message.rb +87 -100
  35. data/lib/onix/price.rb +19 -39
  36. data/lib/onix/product.rb +141 -637
  37. data/lib/onix/product_form_feature.rb +7 -0
  38. data/lib/onix/product_part.rb +89 -0
  39. data/lib/onix/product_supplies_extractor.rb +275 -0
  40. data/lib/onix/product_supply.rb +17 -58
  41. data/lib/onix/publishing_detail.rb +16 -32
  42. data/lib/onix/related_material.rb +4 -3
  43. data/lib/onix/related_product.rb +9 -29
  44. data/lib/onix/related_work.rb +3 -17
  45. data/lib/onix/sales_outlet.rb +2 -10
  46. data/lib/onix/sales_restriction.rb +8 -21
  47. data/lib/onix/sales_rights.rb +1 -5
  48. data/lib/onix/sender.rb +12 -0
  49. data/lib/onix/serializer.rb +156 -0
  50. data/lib/onix/subject.rb +9 -30
  51. data/lib/onix/subset.rb +88 -78
  52. data/lib/onix/supply_detail.rb +42 -0
  53. data/lib/onix/supporting_resource.rb +29 -86
  54. data/lib/onix/tax.rb +9 -18
  55. data/lib/onix/territory.rb +23 -17
  56. data/lib/onix/title_detail.rb +22 -0
  57. data/lib/onix/title_element.rb +32 -0
  58. data/lib/onix/website.rb +3 -16
  59. metadata +53 -34
@@ -1,438 +1,74 @@
1
- require 'onix/identifier'
1
+ require 'onix/collection'
2
+ require 'onix/collection_sequence'
3
+ require 'onix/epub_usage_constraint'
4
+ require 'onix/epub_usage_limit'
5
+ require 'onix/extent'
6
+ require 'onix/language'
7
+ require 'onix/product_form_feature'
8
+ require 'onix/product_part'
9
+ require 'onix/title_detail'
10
+ require 'onix/contributor'
11
+ require 'onix/subject'
2
12
 
3
13
  module ONIX
4
- class TitleElement < SubsetDSL
5
- element "TitleElementLevel", :subset
6
- element "TitleText", :text
7
- element "TitlePrefix", :text
8
- element "TitleWithoutPrefix", :text
9
- element "Subtitle", :text
10
- element "PartNumber", :integer
11
- element "SequenceNumber", :integer
12
-
13
- scope :product_level, lambda { human_code_match(:title_element_level, /Product/)}
14
- scope :collection_level, lambda { human_code_match(:title_element_level, /collection/i)}
15
-
16
- # shortcuts
17
- def level
18
- @title_element_level
19
- end
20
-
21
- # :category: High level
22
- # flatten title string
23
- def title
24
- if @title_text
25
- @title_text
26
- else
27
- if @title_without_prefix
28
- if @title_prefix
29
- "#{@title_prefix} #{@title_without_prefix}"
30
- else
31
- @title_without_prefix
32
- end
33
- end
34
- end
35
- end
36
- end
37
-
38
- class TitleDetail < SubsetDSL
39
- element "TitleType", :subset
40
- elements "TitleElement", :subset
41
-
42
- scope :distinctive_title, lambda { human_code_match(:title_type, /DistinctiveTitle/)}
43
-
44
- def type
45
- @title_type
46
- end
47
-
48
- # :category: High level
49
- # flatten title string
50
- def title
51
- title_element = @title_elements.product_level #select { |te| te.level.human=~/Product/ }
52
- if title_element.size > 0
53
- title_element.first.title
54
- else
55
- nil
56
- end
57
- end
58
- end
59
-
60
- class CollectionSequence < SubsetDSL
61
- element "CollectionSequenceType", :subset
62
- element "CollectionSequenceTypeName", :string
63
- element "CollectionSequenceNumber", :string
64
-
65
- def type
66
- @collection_sequence_number
67
- end
68
-
69
- def number
70
- @collection_sequence_number
71
- end
72
-
73
- def type_name
74
- @collection_sequence_type_name
75
- end
76
- end
77
-
78
- class Collection < SubsetDSL
79
- element "CollectionType", :subset
80
- elements "CollectionIdentifier", :subset
81
- elements "TitleDetail", :subset
82
- elements "CollectionSequence", :subset
83
-
84
- scope :publisher, lambda { human_code_match(:collection_type, "PublisherCollection")}
85
-
86
- # shortcuts
87
- def type
88
- @collection_type
89
- end
90
-
91
- def identifiers
92
- @collection_identifiers
93
- end
94
-
95
- def sequences
96
- @collection_sequences
97
- end
98
-
99
- # :category: High level
100
- # collection title string
101
- def title
102
- if collection_title_element
103
- collection_title_element.title
104
- end
105
- end
106
-
107
- # :category: High level
108
- # collection subtitle string
109
- def subtitle
110
- if collection_title_element
111
- collection_title_element.subtitle
112
- end
113
- end
114
-
115
- def collection_title_element
116
- distinctive_title=@title_details.distinctive_title.first
117
- #select { |td| td.type.human=~/DistinctiveTitle/}.first
118
- if distinctive_title
119
- distinctive_title.title_elements.collection_level.first
120
- #select { |te| te.level.human=~/CollectionLevel/ or te.level.human=~/Subcollection/ }.first
121
- end
122
- end
123
-
124
- end
125
-
126
- # product part use full Product to provide file protection and file size
127
- class ProductPart < SubsetDSL
128
- include EanMethods
129
- include ProprietaryIdMethods
130
-
131
- elements "ProductIdentifier", :subset
132
- element "ProductForm", :subset
133
- element "ProductFormDescription", :text
134
- elements "ProductFormDetail", :subset
135
- elements "ProductContentType", :subset
136
- element "NumberOfCopies", :integer
137
-
138
- # shortcuts
139
- def identifiers
140
- @product_identifiers
141
- end
142
-
143
- def form
144
- @product_form
145
- end
146
-
147
- def form_details
148
- @product_form_details
149
- end
150
-
151
- def content_types
152
- @product_content_types
153
- end
154
-
155
- # full Product if referenced in ONIXMessage
156
- def product
157
- @product
158
- end
159
-
160
- def product=v
161
- @product=v
162
- end
163
-
164
- # this ProductPart is part of Product
165
- def part_of
166
- @part_of
167
- end
168
-
169
- def part_of=v
170
- @part_of=v
171
- end
172
-
173
- # :category: High level
174
- # digital file format string (Epub,Pdf,AmazonKindle)
175
- def file_format
176
- self.file_formats.first.human if self.file_formats.first
177
- end
178
-
179
- def file_mimetype
180
- if self.file_formats.first
181
- self.file_formats.first.mimetype
182
- end
183
- end
184
-
185
- def file_formats
186
- @product_form_details.select { |fd| fd.code =~ /^E1.*/ }
187
- end
188
-
189
- def reflowable?
190
- return true if @product_form_details.select { |fd| fd.code == "E200" }.length > 0
191
- return false if @product_form_details.select { |fd| fd.code == "E201" }.length > 0
192
- end
193
-
194
- # :category: High level
195
- # part file description string
196
- def file_description
197
- @product_form_description
198
- end
199
-
200
- # :category: High level
201
- # raw part file description string without HTML
202
- def raw_file_description
203
- if @product_form_description
204
- Helper.strip_html(@product_form_description).gsub(/\s+/, " ").strip
205
- else
206
- nil
207
- end
208
- end
209
-
210
- # :category: High level
211
- # Protection type string (None, Watermarking, DRM, AdobeDRM)
212
- def protection_type
213
- if product
214
- product.protection_type
215
- else
216
- if part_of
217
- part_of.protection_type
218
- else
219
- nil
220
- end
221
- end
222
- end
223
-
224
- # :category: High level
225
- # List of protections type string (None, Watermarking, DRM, AdobeDRM)
226
- def protections
227
- if product
228
- product.protections
229
- else
230
- if part_of
231
- part_of.protections
232
- else
233
- nil
234
- end
235
- end
236
- end
237
-
238
- # :category: High level
239
- # digital file filesize in bytes
240
- def filesize
241
- if product
242
- product.filesize
243
- else
244
- nil
245
- end
246
- end
247
- end
248
-
249
- class Extent < SubsetDSL
250
- element "ExtentType", :subset
251
- element "ExtentUnit", :subset
252
- element "ExtentValue", :text
253
-
254
- scope :filesize, lambda { human_code_match(:extent_type, /Filesize/)}
255
- scope :page, lambda { human_code_match(:extent_type, /Page/)}
256
-
257
- # shortcuts
258
- def type
259
- @extent_type
260
- end
261
-
262
- def unit
263
- @extent_unit
264
- end
265
-
266
- def value
267
- @extent_value
268
- end
269
-
270
- def bytes
271
- case @extent_unit.human
272
- when "Bytes"
273
- @extent_value.to_i
274
- when "Kbytes"
275
- (@extent_value.to_f*1024).to_i
276
- when "Mbytes"
277
- (@extent_value.to_f*1024*1024).to_i
278
- else
279
- nil
280
- end
281
- end
282
-
283
- def pages
284
- if @extent_unit.human=="Pages"
285
- @extent_value.to_i
286
- else
287
- nil
288
- end
289
- end
290
- end
291
-
292
- class EpubUsageLimit < SubsetDSL
293
- element "EpubUsageUnit", :subset
294
- element "Quantity", :integer
295
-
296
- def unit
297
- @epub_usage_unit
298
- end
299
- end
300
-
301
- class EpubUsageConstraint < SubsetDSL
302
- element "EpubUsageType", :subset
303
- element "EpubUsageStatus", :subset
304
- elements "EpubUsageLimit", :subset
305
-
306
- # shortcuts
307
- def type
308
- @epub_usage_type
309
- end
310
-
311
- def status
312
- @epub_usage_status
313
- end
314
-
315
- def limits
316
- @epub_usage_limits
317
- end
318
- end
319
-
320
- class Language < SubsetDSL
321
- element "LanguageRole", :subset
322
- element "LanguageCode", :subset
323
-
324
- scope :of_text, lambda{human_code_match(:language_role, "LanguageOfText")}
325
-
326
- # shortcuts
327
- def role
328
- @language_role
329
- end
330
-
331
- def code
332
- @language_code
333
- end
334
- end
335
-
336
- class ProductFormFeature < SubsetDSL
337
- element "ProductFormFeatureType", :subset
338
- element "ProductFormFeatureValue", :text
339
- elements "ProductFormFeatureDescription", :text
340
-
341
- # shortcuts
342
- def type
343
- @product_form_feature_type
344
- end
345
-
346
- def value
347
- @product_form_feature_value
348
- end
349
-
350
- def descriptions
351
- @product_form_feature_descriptions
352
- end
353
- end
354
-
355
14
  class DescriptiveDetail < SubsetDSL
356
- element "ProductComposition", :subset
357
- element "ProductForm", :subset
358
- elements "ProductFormDetail", :subset
359
- elements "ProductFormFeature", :subset
360
- element "ProductFormDescription", :text
361
- element "PrimaryContentType", :subset, {:klass=>"ProductContentType"}
362
- elements "ProductContentType", :subset
15
+ element "ProductComposition", :subset, :shortcut => :composition
16
+ element "ProductForm", :subset, :shortcut => :form
17
+ elements "ProductFormDetail", :subset, :shortcut => :form_details
18
+ elements "ProductFormFeature", :subset, :shortcut => :form_features
19
+ element "ProductFormDescription", :text, :shortcut => :file_description
20
+ element "PrimaryContentType", :subset, {:klass => "ProductContentType"}
21
+ elements "ProductContentType", :subset, :shortcut => :content_types
363
22
  elements "EpubTechnicalProtection", :subset
364
23
  elements "EpubUsageConstraint", :subset
365
- elements "ProductPart", :subset
366
-
24
+ elements "ProductPart", :subset, :shortcut => :parts
367
25
  elements "Collection", :subset
368
26
  element "NoCollection", :ignore
369
-
370
27
  elements "TitleDetail", :subset
371
-
372
28
  elements "Contributor", :subset
373
-
374
29
  element "EditionType", :subset
375
30
  element "EditionNumber", :integer
376
31
  element "NoEdition", :ignore
377
-
378
32
  elements "Language", :subset
379
-
380
33
  elements "Extent", :subset
381
-
382
34
  elements "Subject", :subset
383
-
384
35
  elements "AudienceCode", :subset
385
36
 
386
- # shortcuts
387
- def form
388
- @product_form
389
- end
37
+ # @!group Shortcuts
390
38
 
391
- def form_details
392
- @product_form_details
39
+ def pages_extent
40
+ @extents.page.first
393
41
  end
394
42
 
395
- def form_features
396
- @product_form_features
43
+ def product_title_element
44
+ @title_details.distinctive_title.first.title_elements.product_level.first if @title_details.distinctive_title.first
397
45
  end
398
46
 
399
- def composition
400
- @product_composition
47
+ def file_formats
48
+ @product_form_details.select { |fd| fd.code =~ /^E1.*/ }
401
49
  end
402
50
 
403
- def parts
404
- @product_parts
405
- end
51
+ # @!endgroup
406
52
 
407
- def content_types
408
- @product_content_types
409
- end
53
+ # @!group High level
410
54
 
411
- # :category: High level
412
55
  # product title string
56
+ # @return [String]
413
57
  def title
414
58
  product_title_element.title if product_title_element
415
59
  end
416
60
 
417
- # :category: High level
418
61
  # product subtitle string
62
+ # @return [String]
419
63
  def subtitle
420
64
  product_title_element.subtitle if product_title_element
421
65
  end
422
66
 
423
- def product_title_element
424
- @title_details.distinctive_title.first.title_elements.product_level.first if @title_details.distinctive_title.first
425
- end
426
-
427
- def pages_extent
428
- @extents.page.first
429
- end
430
-
67
+ # page count
68
+ # @return [Integer]
431
69
  def pages
432
70
  if pages_extent
433
71
  pages_extent.pages
434
- else
435
- nil
436
72
  end
437
73
  end
438
74
 
@@ -440,6 +76,8 @@ module ONIX
440
76
  @extents.filesize.first
441
77
  end
442
78
 
79
+ # file size in bytes
80
+ # @return [Integer]
443
81
  def filesize
444
82
  if filesize_extent
445
83
  filesize_extent.bytes
@@ -448,18 +86,30 @@ module ONIX
448
86
  end
449
87
  end
450
88
 
89
+ # is digital ?
90
+ # @return [Boolean]
451
91
  def digital?
452
- if @product_form and @product_form.human=~/Digital/
92
+ if @product_form and @product_form.human =~ /Digital/
453
93
  true
454
94
  else
455
95
  false
456
96
  end
457
97
  end
458
98
 
99
+ # digital offer has DRM ?
100
+ # @return [Boolean]
101
+ def drmized?
102
+ @protections.any? { |p| p =~ /Drm/ }
103
+ end
104
+
105
+ # is digital offer streaming ?
106
+ # @return [Boolean]
459
107
  def streaming?
460
- @product_form.code=="EC"
108
+ @product_form.code == "EC"
461
109
  end
462
110
 
111
+ # is digital offer audio ?
112
+ # @return [Boolean]
463
113
  def audio?
464
114
  not audio_formats.empty?
465
115
  end
@@ -472,33 +122,35 @@ module ONIX
472
122
  @product_form_details.select { |fd| fd.code =~ /^A.*/ }
473
123
  end
474
124
 
125
+ # is digital offer a bundle ?
126
+ # @return [Boolean]
475
127
  def bundle?
476
- @product_composition.human=="MultipleitemRetailProduct"
128
+ @product_composition.human == "MultipleitemRetailProduct"
477
129
  end
478
130
 
131
+ # digital file format string (Epub,Pdf,AmazonKindle)
132
+ # @return [String]
479
133
  def file_format
480
- self.file_formats.first.human if self.file_formats.first
134
+ file_formats.first.human if file_formats.first
481
135
  end
482
136
 
137
+ # digital file format mimetype
138
+ # @return [String]
483
139
  def file_mimetype
484
- if self.file_formats.first
485
- self.file_formats.first.mimetype
140
+ if file_formats.first
141
+ file_formats.first.mimetype
486
142
  end
487
143
  end
488
144
 
489
- def file_formats
490
- @product_form_details.select { |fd| fd.code =~ /^E1.*/ }
491
- end
492
-
145
+ # is digital file reflowable ?
146
+ # @return [Boolean]
493
147
  def reflowable?
494
148
  return true if @product_form_details.select { |fd| fd.code == "E200" }.length > 0
495
149
  return false if @product_form_details.select { |fd| fd.code == "E201" }.length > 0
496
150
  end
497
151
 
498
- def file_description
499
- @product_form_description
500
- end
501
-
152
+ # protection type string
153
+ # @return [String]
502
154
  def protection_type
503
155
  if @epub_technical_protections.length > 0
504
156
  if @epub_technical_protections.length == 1
@@ -509,18 +161,18 @@ module ONIX
509
161
  end
510
162
  end
511
163
 
164
+ # protections string array
165
+ # @return [Array<String>]
512
166
  def protections
513
167
  return nil if @epub_technical_protections.length == 0
514
-
515
168
  @epub_technical_protections.map(&:human)
516
169
  end
517
170
 
171
+ # language of text
518
172
  def language_of_text
519
- l=@languages.of_text.first
173
+ l = @languages.of_text.first
520
174
  if l
521
175
  l.code
522
- else
523
- nil
524
176
  end
525
177
  end
526
178
 
@@ -528,25 +180,46 @@ module ONIX
528
180
  @collections.publisher.first
529
181
  end
530
182
 
183
+ # publisher collection title
184
+ # @return [String]
531
185
  def publisher_collection_title
532
186
  if self.publisher_collection
533
187
  self.publisher_collection.title
534
188
  end
535
189
  end
536
190
 
191
+ # BISAC categories
192
+ # @return [Array<Subject>]
537
193
  def bisac_categories
538
194
  @subjects.bisac
539
195
  end
540
196
 
197
+ # BISAC categories identifiers string array (eg: FIC000000)
198
+ # @return [Array<String>]
199
+ def bisac_categories_codes
200
+ self.bisac_categories.map { |c| c.code }.uniq
201
+ end
202
+
203
+ # BISAC categories
204
+ # @return [Array<Subject>]
541
205
  def clil_categories
542
206
  @subjects.clil
543
207
  end
544
208
 
209
+ # CLIL categories identifier string array
210
+ # @return [Array<String>]
211
+ def clil_categories_codes
212
+ self.clil_categories.map { |c| c.code }.uniq
213
+ end
214
+
215
+ # keywords string array
545
216
  def keywords
546
- kws=@subjects.keyword.map { |kw| kw.heading_text }.compact
547
- kws=kws.flat_map { |kw| kw.split(/;|,|\n/) }.map { |kw| kw.strip }
548
- kws.reject!{|k| k==""}
217
+ kws = @subjects.keyword.map { |kw| kw.heading_text }.compact
218
+ kws = kws.flat_map { |kw| kw.split(/;|,|\n/) }.map { |kw| kw.strip }
219
+ kws.reject! { |k| k == "" }
549
220
  kws
550
221
  end
222
+
223
+ # @!endgroup
551
224
  end
552
225
  end