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.
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