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,35 +1,14 @@
1
1
  module ONIX
2
2
  class Subject < SubsetDSL
3
3
  element "MainSubject", :bool
4
- element "SubjectSchemeIdentifier", :subset
5
- element "SubjectSchemeName", :text
6
- element "SubjectSchemeVersion", :text
7
- element "SubjectCode", :text
8
- element "SubjectHeadingText", :text
9
-
10
- scope :bisac, lambda{ human_code_match(:subject_scheme_identifier, "BisacSubjectHeading") }
11
- scope :clil, lambda{ human_code_match(:subject_scheme_identifier, "Clil") }
12
- scope :keyword, lambda{ human_code_match(:subject_scheme_identifier, "Keywords") }
13
-
14
- # shortcuts
15
- def code
16
- @subject_code
17
- end
18
-
19
- def heading_text
20
- @subject_heading_text
21
- end
22
-
23
- def scheme_identifier
24
- @subject_scheme_identifier
25
- end
26
-
27
- def scheme_name
28
- @subject_scheme_name
29
- end
30
-
31
- def scheme_version
32
- @subject_scheme_version
33
- end
4
+ element "SubjectSchemeIdentifier", :subset, :shortcut => :scheme_identifier
5
+ element "SubjectSchemeName", :text, :shortcut => :scheme_name
6
+ element "SubjectSchemeVersion", :text, :shortcut => :scheme_version
7
+ element "SubjectCode", :text, :shortcut => :code
8
+ element "SubjectHeadingText", :text, :shortcut => :heading_text
9
+
10
+ scope :bisac, lambda { human_code_match(:subject_scheme_identifier, "BisacSubjectHeading") }
11
+ scope :clil, lambda { human_code_match(:subject_scheme_identifier, "Clil") }
12
+ scope :keyword, lambda { human_code_match(:subject_scheme_identifier, "Keywords") }
34
13
  end
35
14
  end
@@ -1,20 +1,20 @@
1
1
  module ONIX
2
2
  class ShortToRef
3
3
  def self.names
4
- @shortnames||=YAML.load(File.open(File.dirname(__FILE__) + "/../../data/shortnames.yml"))
4
+ @shortnames ||= YAML.load(File.open(File.dirname(__FILE__) + "/../../data/shortnames.yml"))
5
5
  end
6
6
  end
7
7
 
8
8
  class RefToShort
9
9
  def self.names
10
- @refnames||=ShortToRef.names.invert
10
+ @refnames ||= ShortToRef.names.invert
11
11
  end
12
12
  end
13
13
 
14
14
  TagNameMatcher = Struct.new(:tag_name) do
15
15
  def ===(target)
16
16
  if target.element?
17
- name=target.name
17
+ name = target.name
18
18
  name.casecmp(tag_name) == 0 or ShortToRef.names[name] == tag_name
19
19
  else
20
20
  false
@@ -25,18 +25,17 @@ module ONIX
25
25
  class Subset
26
26
  # instanciate Subset form Nokogiri::XML::Element
27
27
  def self.parse(n)
28
- o=self.new
28
+ o = self.new
29
29
  o.parse(n)
30
30
  o
31
31
  end
32
32
 
33
33
  # parse Nokogiri::XML::Element
34
- def parse(n)
35
- end
34
+ def parse(n) end
36
35
 
37
36
  def unsupported(tag)
38
- # raise SubsetUnsupported,tag.name
39
- # puts "SubsetUnsupported: #{self.class}##{tag.name} (#{ShortToRef.names[tag.name]})"
37
+ # raise SubsetUnsupported,tag.name
38
+ # puts "SubsetUnsupported: #{self.class}##{tag.name} (#{ShortToRef.names[tag.name]})"
40
39
  end
41
40
 
42
41
  def tag_match(v)
@@ -79,31 +78,36 @@ module ONIX
79
78
  ['ouse', 'ouses']]
80
79
  end
81
80
 
82
- def initialize(name, type, options={})
83
- @name=name
84
- @type=type
85
- @pluralize=true
81
+ def initialize(name, type, options = {})
82
+ @name = name
83
+ @type = type
84
+ @pluralize = true
86
85
  @short = false
87
- @array=false
86
+ @array = false
88
87
  @parse_lambda = nil
89
88
  @serialize_lambda = nil
90
89
  if options[:array]
91
- @array=true
90
+ @array = true
92
91
  end
93
- if options[:pluralize]==false
94
- @pluralize=false
92
+ if options[:pluralize] == false
93
+ @pluralize = false
95
94
  end
96
95
 
97
- @parse_lambda=options[:parse_lambda]
98
- @serialize_lambda=options[:serialize_lambda]
96
+ @parse_lambda = options[:parse_lambda]
97
+ @serialize_lambda = options[:serialize_lambda]
98
+ @shortcut = options[:shortcut]
99
99
 
100
100
  if options[:klass]
101
- @klass_name=options[:klass]
101
+ @klass_name = options[:klass]
102
102
  else
103
- @klass_name=name
103
+ @klass_name = name
104
104
  end
105
105
  end
106
106
 
107
+ def shortcut
108
+ @shortcut
109
+ end
110
+
107
111
  def parse_lambda(v)
108
112
  if @parse_lambda
109
113
  @parse_lambda.call(v)
@@ -133,7 +137,7 @@ module ONIX
133
137
  end
134
138
 
135
139
  def underscore_name
136
- @underscore_name||=_underscore_name
140
+ @underscore_name ||= _underscore_name
137
141
  end
138
142
 
139
143
  def class_name
@@ -141,14 +145,15 @@ module ONIX
141
145
  end
142
146
 
143
147
  def to_sym
144
- @sym||=self.underscore_name.to_sym
148
+ @sym ||= self.underscore_name.to_sym
145
149
  end
146
150
 
147
151
  def to_instance
148
- @instance||="@"+self.underscore_name
152
+ @instance ||= "@" + self.underscore_name
149
153
  end
150
154
 
151
155
  private
156
+
152
157
  def pluralize(str)
153
158
  rex = /(#{self.class.inflectors.map { |si, pl| si }.join('|')})$/i
154
159
  hash = Hash[*self.class.inflectors.flatten]
@@ -169,33 +174,33 @@ module ONIX
169
174
  class SubsetArray < Array
170
175
  def human_code_match(k, p)
171
176
  case p
172
- when Regexp
173
- self.class.new(self.select { |v|
174
- code=v.instance_variable_get("@"+k.to_s)
175
- code and code.human =~ p
176
- })
177
- when Array
178
- self.class.new(self.select { |v|
179
- code=v.instance_variable_get("@"+k.to_s)
180
- code and p.include?(code.human)
181
- })
182
- else
183
- self.class.new(self.select { |v|
184
- code=v.instance_variable_get("@"+k.to_s)
185
- code and code.human == p
186
- })
177
+ when Regexp
178
+ self.class.new(self.select { |v|
179
+ code = v.instance_variable_get("@" + k.to_s)
180
+ code and code.human =~ p
181
+ })
182
+ when Array
183
+ self.class.new(self.select { |v|
184
+ code = v.instance_variable_get("@" + k.to_s)
185
+ code and p.include?(code.human)
186
+ })
187
+ else
188
+ self.class.new(self.select { |v|
189
+ code = v.instance_variable_get("@" + k.to_s)
190
+ code and code.human == p
191
+ })
187
192
  end
188
193
  end
189
194
 
190
195
  def code_match(k, p)
191
196
  case p
192
- when Regexp
193
- self.class.new(self.select { |v|
194
- code=v.instance_variable_get("@"+k.to_s)
195
- code.code =~ p
196
- })
197
- else
198
- self.class.new(self.select { |v| v.instance_variable_get("@"+k.to_s).code == p })
197
+ when Regexp
198
+ self.class.new(self.select { |v|
199
+ code = v.instance_variable_get("@" + k.to_s)
200
+ code.code =~ p
201
+ })
202
+ else
203
+ self.class.new(self.select { |v| v.instance_variable_get("@" + k.to_s).code == p })
199
204
  end
200
205
  end
201
206
  end
@@ -207,55 +212,61 @@ module ONIX
207
212
  end
208
213
 
209
214
  def self._ancestor_registered_scopes
210
- els=self.registered_scopes
211
- sup=self
215
+ els = self.registered_scopes
216
+ sup = self
212
217
  while sup.respond_to?(:registered_scopes)
213
218
  els.merge!(sup.registered_scopes) if sup.registered_scopes
214
- sup=sup.superclass
219
+ sup = sup.superclass
215
220
  end
216
221
  els
217
222
  end
218
223
 
219
224
  def self.ancestor_registered_scopes
220
- @ancestors_registered_scopes||=_ancestor_registered_scopes
225
+ @ancestors_registered_scopes ||= _ancestor_registered_scopes
221
226
  end
222
227
 
223
228
  def self.registered_scopes
224
- @scopes||{}
229
+ @scopes || {}
225
230
  end
226
231
 
227
- def self.element(name, type, options={})
232
+ def self.element(name, type, options = {})
228
233
  @elements ||= {}
229
- @elements[name]=ElementParser.new(name, type, options)
230
- short_name=self.ref_to_short(name)
234
+ @elements[name] = ElementParser.new(name, type, options)
235
+ short_name = self.ref_to_short(name)
231
236
  if short_name
232
- @elements[short_name]=@elements[name].dup
237
+ @elements[short_name] = @elements[name].dup
233
238
  @elements[short_name].short = true
234
239
  end
235
240
  attr_accessor @elements[name].to_sym
241
+ if @elements[name].shortcut
242
+ current_element = @elements[name]
243
+ define_method current_element.shortcut do |args = nil|
244
+ instance_variable_get(current_element.to_instance)
245
+ end
246
+ end
236
247
  end
237
248
 
238
249
  # shortcut for element :array=>true
239
- def self.elements(name, type, options={})
250
+ def self.elements(name, type, options = {})
240
251
  self.element(name, type, options.merge(:array => true))
241
252
  end
242
253
 
243
254
  def self._ancestors_registered_elements
244
- els=self.registered_elements
245
- sup=self
255
+ els = self.registered_elements
256
+ sup = self
246
257
  while sup.respond_to?(:registered_elements)
247
258
  els.merge!(sup.registered_elements) if sup.registered_elements
248
- sup=sup.superclass
259
+ sup = sup.superclass
249
260
  end
250
261
  els
251
262
  end
252
263
 
253
264
  def self.ancestors_registered_elements
254
- @ancestors_registered_elements||=_ancestors_registered_elements
265
+ @ancestors_registered_elements ||= _ancestors_registered_elements
255
266
  end
256
267
 
257
268
  def self.registered_elements
258
- @elements||{}
269
+ @elements || {}
259
270
  end
260
271
 
261
272
  def initialize
@@ -294,23 +305,23 @@ module ONIX
294
305
  def parse(n)
295
306
  n.elements.each do |t|
296
307
  name = t.name
297
- e=self.class.ancestors_registered_elements[name]
308
+ e = self.class.ancestors_registered_elements[name]
298
309
  if e
299
310
  case e.type
300
- when :subset
301
- val=self.class.get_class(e.class_name).parse(t)
302
- when :text
303
- val=t.text
304
- when :integer
305
- val=t.text.to_i
306
- when :float
307
- val=t.text.to_f
308
- when :bool
309
- val=true
310
- when :ignore
311
- val=nil
312
- else
313
- val=t.text
311
+ when :subset
312
+ val = self.class.get_class(e.class_name).parse(t)
313
+ when :text
314
+ val = t.text
315
+ when :integer
316
+ val = t.text.to_i
317
+ when :float
318
+ val = t.text.to_f
319
+ when :bool
320
+ val = true
321
+ when :ignore
322
+ val = nil
323
+ else
324
+ val = t.text
314
325
  end
315
326
  if val
316
327
  if e.is_array?
@@ -326,9 +337,8 @@ module ONIX
326
337
  end
327
338
 
328
339
  def unsupported(tag)
329
- # raise SubsetUnsupported,tag.name
330
- # puts "SubsetUnsupported: #{self.class}##{tag.name} (#{self.class.short_to_ref(tag.name)})"
340
+ # raise SubsetUnsupported,tag.name
341
+ # puts "SubsetUnsupported: #{self.class}##{tag.name} (#{self.class.short_to_ref(tag.name)})"
331
342
  end
332
-
333
343
  end
334
344
  end
@@ -0,0 +1,42 @@
1
+ require 'onix/price'
2
+
3
+ module ONIX
4
+ class SupplyDetail < SubsetDSL
5
+ elements "Supplier", :subset
6
+ element "ProductAvailability", :subset, :shortcut => :availability
7
+ elements "SupplyDate", :subset
8
+ elements "Price", :subset
9
+ element "UnpricedItemType", :subset
10
+
11
+ # @!group Shortcuts
12
+ def distributors
13
+ @suppliers.select { |s| s.role.human =~ /Distributor/ }.uniq
14
+ end
15
+
16
+ # @!endgroup
17
+
18
+ # @!group High level
19
+ # is supply available ?
20
+ # @return [Boolean]
21
+ def available?
22
+ ["Available", "NotYetAvailable", "InStock", "ToOrder", "Pod"].include?(@product_availability.human)
23
+ end
24
+
25
+ # does supply can be sold separately ?
26
+ # @return [Boolean]
27
+ def sold_separately?
28
+ @product_availability.human != "NotSoldSeparately"
29
+ end
30
+
31
+ # supply availability date
32
+ # @return [Date]
33
+ def availability_date
34
+ av = @supply_dates.availability.first
35
+ if av
36
+ av.date
37
+ end
38
+ end
39
+
40
+ # @!endgroup
41
+ end
42
+ end
@@ -2,62 +2,40 @@ require 'onix/date'
2
2
 
3
3
  module ONIX
4
4
  class ResourceVersionFeature < SubsetDSL
5
- element "ResourceVersionFeatureType", :subset
6
- elements "FeatureNote", :text
7
- element "FeatureValue", :text, :serialize_lambda => lambda {|v| v.class == SupportingResourceFileFormat ? v.code : v}
5
+ element "ResourceVersionFeatureType", :subset, :shortcut => :type
6
+ elements "FeatureNote", :text, :shortcut => :notes
7
+ element "FeatureValue", :text, {
8
+ :shortcut => :value,
9
+ :serialize_lambda => lambda { |v| v.class == SupportingResourceFileFormat ? v.code : v }
10
+ }
8
11
 
9
- scope :image_pixels_width, lambda { human_code_match(:resource_version_feature_type,"ImageWidthInPixels") }
10
- scope :image_pixels_height, lambda { human_code_match(:resource_version_feature_type,"ImageHeightInPixels") }
11
- scope :md5_hash, lambda { human_code_match(:resource_version_feature_type,"Md5HashValue")}
12
-
13
- def type
14
- @resource_version_feature_type
15
- end
16
-
17
- def value
18
- @feature_value
19
- end
20
-
21
- def notes
22
- @feature_notes
23
- end
12
+ scope :image_pixels_width, lambda { human_code_match(:resource_version_feature_type, "ImageWidthInPixels") }
13
+ scope :image_pixels_height, lambda { human_code_match(:resource_version_feature_type, "ImageHeightInPixels") }
14
+ scope :md5_hash, lambda { human_code_match(:resource_version_feature_type, "Md5HashValue") }
24
15
 
25
16
  def parse(n)
26
17
  super
27
18
 
28
- if @resource_version_feature_type.human=="FileFormat"
29
- @feature_value=SupportingResourceFileFormat.from_code(@feature_value)
19
+ if @resource_version_feature_type.human == "FileFormat"
20
+ @feature_value = SupportingResourceFileFormat.from_code(@feature_value)
30
21
  end
31
22
  end
32
23
  end
33
24
 
34
25
  class ResourceVersion < SubsetDSL
35
- element "ResourceForm", :subset
36
- elements "ResourceVersionFeature", :subset
37
- elements "ResourceLink", :text
26
+ element "ResourceForm", :subset, :shortcut => :form
27
+ elements "ResourceVersionFeature", :subset, :shortcut => :features
28
+ elements "ResourceLink", :text, :shortcut => :links
38
29
  elements "ContentDate", :subset
39
30
 
40
- # shortcuts
41
- def form
42
- @resource_form
43
- end
44
-
45
- def links
46
- @resource_links
47
- end
48
-
49
- def features
50
- @resource_version_features
51
- end
52
-
53
31
  def filename
54
- if @resource_form.human=="DownloadableFile"
32
+ if @resource_form.human == "DownloadableFile"
55
33
  @resource_links.first
56
34
  end
57
35
  end
58
36
 
59
37
  def file_format_feature
60
- @resource_version_features.select { |f| f.type.human=="FileFormat" }.first
38
+ @resource_version_features.select { |f| f.type.human == "FileFormat" }.first
61
39
  end
62
40
 
63
41
  def file_format
@@ -124,55 +102,25 @@ module ONIX
124
102
  end
125
103
 
126
104
  class ResourceFeature < SubsetDSL
127
- element "ResourceFeatureType", :subset
128
- element "FeatureValue", :text
129
- elements "FeatureNotes", :text
130
-
131
- scope :caption, lambda { human_code_match(:resource_feature_type, "Caption")}
132
-
133
- # shortcuts
134
- def type
135
- @resource_feature_type
136
- end
105
+ element "ResourceFeatureType", :subset, :shortcut => :type
106
+ element "FeatureValue", :text, :shortcut => :value
107
+ elements "FeatureNotes", :text, :shortcut => :notes
137
108
 
138
- def value
139
- @feature_value
140
- end
141
-
142
- def notes
143
- @feature_notes
144
- end
109
+ scope :caption, lambda { human_code_match(:resource_feature_type, "Caption") }
145
110
  end
146
111
 
147
112
  class SupportingResource < SubsetDSL
148
- element "ResourceContentType", :subset
149
- element "ContentAudience", :subset
150
- element "ResourceMode", :subset
151
- elements "ResourceVersion", :subset
152
- elements "ResourceFeature", :subset
153
-
154
- scope :front_cover, lambda { human_code_match(:resource_content_type, "FrontCover")}
155
- scope :sample_content, lambda { human_code_match(:resource_content_type, "SampleContent")}
156
-
157
- scope :image, lambda {human_code_match(:resource_mode, "Image")}
158
- scope :text, lambda {human_code_match(:resource_mode, "Text")}
159
-
160
- # shortcuts
161
- def type
162
- @resource_content_type
163
- end
113
+ element "ResourceContentType", :subset, :shortcut => :type
114
+ element "ContentAudience", :subset, :shortcut => :target_audience
115
+ element "ResourceMode", :subset, :shortcut => :mode
116
+ elements "ResourceVersion", :subset, :shortcut => :versions
117
+ elements "ResourceFeature", :subset, :shortcut => :features
164
118
 
165
- def mode
166
- @resource_mode
167
- end
168
-
169
- def versions
170
- @resource_versions
171
- end
119
+ scope :front_cover, lambda { human_code_match(:resource_content_type, "FrontCover") }
120
+ scope :sample_content, lambda { human_code_match(:resource_content_type, "SampleContent") }
172
121
 
173
- def features
174
- @resource_features
175
- end
122
+ scope :image, lambda { human_code_match(:resource_mode, "Image") }
123
+ scope :text, lambda { human_code_match(:resource_mode, "Text") }
176
124
 
177
125
  def caption_feature
178
126
  self.features.caption.first
@@ -183,10 +131,5 @@ module ONIX
183
131
  self.caption_feature.value
184
132
  end
185
133
  end
186
-
187
- def target_audience
188
- @content_audience
189
- end
190
-
191
134
  end
192
135
  end