im_onix 1.1.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (311) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -6
  3. data/README.md +1 -1
  4. data/bin/html_codelist_to_yml.rb +10 -6
  5. data/bin/onix_bench.rb +25 -4
  6. data/bin/onix_pp.rb +26 -26
  7. data/bin/onix_serialize.rb +12 -16
  8. data/data/codelists/codelist-1.yml +4 -5
  9. data/data/codelists/codelist-10.yml +13 -11
  10. data/data/codelists/codelist-100.yml +1 -0
  11. data/data/codelists/codelist-102.yml +3 -2
  12. data/data/codelists/codelist-11.yml +2 -2
  13. data/data/codelists/codelist-12.yml +8 -3
  14. data/data/codelists/codelist-121.yml +46 -17
  15. data/data/codelists/codelist-13.yml +3 -0
  16. data/data/codelists/codelist-139.yml +83 -9
  17. data/data/codelists/codelist-141.yml +4 -4
  18. data/data/codelists/codelist-142.yml +2 -2
  19. data/data/codelists/codelist-143.yml +11 -0
  20. data/data/codelists/codelist-144.yml +2 -2
  21. data/data/codelists/codelist-145.yml +4 -1
  22. data/data/codelists/codelist-147.yml +18 -2
  23. data/data/codelists/codelist-149.yml +1 -0
  24. data/data/codelists/codelist-15.yml +2 -1
  25. data/data/codelists/codelist-150.yml +46 -26
  26. data/data/codelists/codelist-151.yml +4 -1
  27. data/data/codelists/codelist-153.yml +19 -4
  28. data/data/codelists/codelist-154.yml +4 -2
  29. data/data/codelists/codelist-155.yml +3 -1
  30. data/data/codelists/codelist-156.yml +1 -0
  31. data/data/codelists/codelist-158.yml +18 -0
  32. data/data/codelists/codelist-159.yml +1 -1
  33. data/data/codelists/codelist-16.yml +3 -0
  34. data/data/codelists/codelist-160.yml +2 -0
  35. data/data/codelists/codelist-162.yml +2 -0
  36. data/data/codelists/codelist-163.yml +8 -3
  37. data/data/codelists/codelist-165.yml +3 -0
  38. data/data/codelists/codelist-166.yml +7 -2
  39. data/data/codelists/codelist-167.yml +6 -0
  40. data/data/codelists/codelist-168.yml +1 -0
  41. data/data/codelists/codelist-169.yml +2 -2
  42. data/data/codelists/codelist-17.yml +20 -2
  43. data/data/codelists/codelist-170.yml +5 -1
  44. data/data/codelists/codelist-171.yml +1 -0
  45. data/data/codelists/codelist-173.yml +1 -1
  46. data/data/codelists/codelist-175.yml +113 -35
  47. data/data/codelists/codelist-176.yml +2 -2
  48. data/data/codelists/codelist-177.yml +1 -0
  49. data/data/codelists/codelist-178.yml +6 -0
  50. data/data/codelists/codelist-179.yml +1 -0
  51. data/data/codelists/codelist-18.yml +3 -1
  52. data/data/codelists/codelist-184.yml +1 -0
  53. data/data/codelists/codelist-19.yml +5 -4
  54. data/data/codelists/codelist-196.yml +16 -4
  55. data/data/codelists/codelist-197.yml +2 -0
  56. data/data/codelists/codelist-198.yml +7 -0
  57. data/data/codelists/codelist-2.yml +6 -6
  58. data/data/codelists/codelist-20.yml +10 -1
  59. data/data/codelists/codelist-203.yml +1 -1
  60. data/data/codelists/codelist-204.yml +4 -0
  61. data/data/codelists/codelist-21.yml +24 -19
  62. data/data/codelists/codelist-215.yml +9 -0
  63. data/data/codelists/codelist-216.yml +11 -0
  64. data/data/codelists/codelist-217.yml +9 -0
  65. data/data/codelists/codelist-218.yml +5 -0
  66. data/data/codelists/codelist-219.yml +5 -0
  67. data/data/codelists/codelist-22.yml +5 -4
  68. data/data/codelists/codelist-220.yml +10 -0
  69. data/data/codelists/codelist-221.yml +6 -0
  70. data/data/codelists/codelist-222.yml +4 -0
  71. data/data/codelists/codelist-223.yml +4 -0
  72. data/data/codelists/codelist-224.yml +8 -0
  73. data/data/codelists/codelist-225.yml +4 -0
  74. data/data/codelists/codelist-226.yml +7 -0
  75. data/data/codelists/codelist-227.yml +21 -0
  76. data/data/codelists/codelist-228.yml +3 -0
  77. data/data/codelists/codelist-229.yml +5 -0
  78. data/data/codelists/codelist-23.yml +5 -3
  79. data/data/codelists/codelist-230.yml +8 -0
  80. data/data/codelists/codelist-238.yml +23 -0
  81. data/data/codelists/codelist-239.yml +4 -0
  82. data/data/codelists/codelist-24.yml +3 -0
  83. data/data/codelists/codelist-240.yml +6 -0
  84. data/data/codelists/codelist-241.yml +9 -0
  85. data/data/codelists/codelist-242.yml +24 -0
  86. data/data/codelists/codelist-243.yml +9 -0
  87. data/data/codelists/codelist-244.yml +3 -0
  88. data/data/codelists/codelist-245.yml +5 -0
  89. data/data/codelists/codelist-246.yml +4 -0
  90. data/data/codelists/codelist-247.yml +4 -0
  91. data/data/codelists/codelist-25.yml +4 -2
  92. data/data/codelists/codelist-26.yml +28 -18
  93. data/data/codelists/codelist-27.yml +35 -19
  94. data/data/codelists/codelist-28.yml +2 -1
  95. data/data/codelists/codelist-29.yml +8 -3
  96. data/data/codelists/codelist-3.yml +5 -2
  97. data/data/codelists/codelist-30.yml +6 -2
  98. data/data/codelists/codelist-32.yml +7 -0
  99. data/data/codelists/codelist-33.yml +6 -2
  100. data/data/codelists/codelist-34.yml +0 -11
  101. data/data/codelists/codelist-38.yml +1 -1
  102. data/data/codelists/codelist-39.yml +2 -2
  103. data/data/codelists/codelist-41.yml +4 -3
  104. data/data/codelists/codelist-42.yml +0 -12
  105. data/data/codelists/codelist-43.yml +3 -1
  106. data/data/codelists/codelist-44.yml +16 -3
  107. data/data/codelists/codelist-45.yml +8 -3
  108. data/data/codelists/codelist-46.yml +4 -4
  109. data/data/codelists/codelist-48.yml +20 -2
  110. data/data/codelists/codelist-49.yml +268 -1
  111. data/data/codelists/codelist-5.yml +6 -3
  112. data/data/codelists/codelist-51.yml +11 -5
  113. data/data/codelists/codelist-55.yml +2 -2
  114. data/data/codelists/codelist-57.yml +1 -0
  115. data/data/codelists/codelist-58.yml +14 -12
  116. data/data/codelists/codelist-59.yml +10 -1
  117. data/data/codelists/codelist-6.yml +39 -39
  118. data/data/codelists/codelist-60.yml +1 -1
  119. data/data/codelists/codelist-62.yml +2 -1
  120. data/data/codelists/codelist-64.yml +3 -2
  121. data/data/codelists/codelist-65.yml +1 -0
  122. data/data/codelists/codelist-68.yml +2 -2
  123. data/data/codelists/codelist-69.yml +2 -2
  124. data/data/codelists/codelist-7.yml +21 -17
  125. data/data/codelists/codelist-71.yml +16 -6
  126. data/data/codelists/codelist-73.yml +7 -5
  127. data/data/codelists/codelist-74.yml +59 -31
  128. data/data/codelists/codelist-75.yml +1 -1
  129. data/data/codelists/codelist-76.yml +3 -3
  130. data/data/codelists/codelist-78.yml +52 -26
  131. data/data/codelists/codelist-79.yml +16 -7
  132. data/data/codelists/codelist-8.yml +3 -3
  133. data/data/codelists/codelist-80.yml +6 -5
  134. data/data/codelists/codelist-81.yml +8 -5
  135. data/data/codelists/codelist-83.yml +3 -2
  136. data/data/codelists/codelist-85.yml +1 -1
  137. data/data/codelists/codelist-9.yml +7 -3
  138. data/data/codelists/codelist-90.yml +2 -2
  139. data/data/codelists/codelist-91.yml +11 -11
  140. data/data/codelists/codelist-92.yml +1 -1
  141. data/data/codelists/codelist-93.yml +9 -6
  142. data/data/codelists/codelist-96.yml +45 -40
  143. data/data/codelists/codelist-98.yml +6 -3
  144. data/data/codelists/codelist-99.yml +8 -5
  145. data/data/onix21/codelists/codelist-1.yml +2 -2
  146. data/data/onix21/codelists/codelist-10.yml +12 -12
  147. data/data/onix21/codelists/codelist-11.yml +2 -2
  148. data/data/onix21/codelists/codelist-12.yml +3 -3
  149. data/data/onix21/codelists/codelist-121.yml +9 -9
  150. data/data/onix21/codelists/codelist-13.yml +1 -1
  151. data/data/onix21/codelists/codelist-139.yml +6 -6
  152. data/data/onix21/codelists/codelist-141.yml +4 -4
  153. data/data/onix21/codelists/codelist-142.yml +2 -2
  154. data/data/onix21/codelists/codelist-145.yml +2 -2
  155. data/data/onix21/codelists/codelist-147.yml +2 -2
  156. data/data/onix21/codelists/codelist-148.yml +1 -1
  157. data/data/onix21/codelists/codelist-149.yml +1 -1
  158. data/data/onix21/codelists/codelist-15.yml +1 -1
  159. data/data/onix21/codelists/codelist-150.yml +23 -23
  160. data/data/onix21/codelists/codelist-151.yml +1 -1
  161. data/data/onix21/codelists/codelist-153.yml +3 -3
  162. data/data/onix21/codelists/codelist-154.yml +2 -2
  163. data/data/onix21/codelists/codelist-155.yml +1 -1
  164. data/data/onix21/codelists/codelist-158.yml +2 -2
  165. data/data/onix21/codelists/codelist-159.yml +1 -1
  166. data/data/onix21/codelists/codelist-163.yml +2 -2
  167. data/data/onix21/codelists/codelist-166.yml +1 -1
  168. data/data/onix21/codelists/codelist-169.yml +2 -2
  169. data/data/onix21/codelists/codelist-17.yml +2 -2
  170. data/data/onix21/codelists/codelist-173.yml +1 -1
  171. data/data/onix21/codelists/codelist-175.yml +23 -23
  172. data/data/onix21/codelists/codelist-176.yml +2 -2
  173. data/data/onix21/codelists/codelist-18.yml +1 -1
  174. data/data/onix21/codelists/codelist-196.yml +4 -4
  175. data/data/onix21/codelists/codelist-2.yml +6 -6
  176. data/data/onix21/codelists/codelist-203.yml +1 -1
  177. data/data/onix21/codelists/codelist-21.yml +1 -1
  178. data/data/onix21/codelists/codelist-216.yml +2 -2
  179. data/data/onix21/codelists/codelist-218.yml +1 -1
  180. data/data/onix21/codelists/codelist-22.yml +3 -3
  181. data/data/onix21/codelists/codelist-23.yml +2 -2
  182. data/data/onix21/codelists/codelist-25.yml +2 -2
  183. data/data/onix21/codelists/codelist-26.yml +18 -18
  184. data/data/onix21/codelists/codelist-27.yml +18 -18
  185. data/data/onix21/codelists/codelist-28.yml +1 -1
  186. data/data/onix21/codelists/codelist-29.yml +3 -3
  187. data/data/onix21/codelists/codelist-3.yml +2 -2
  188. data/data/onix21/codelists/codelist-30.yml +1 -1
  189. data/data/onix21/codelists/codelist-32.yml +1 -1
  190. data/data/onix21/codelists/codelist-33.yml +2 -2
  191. data/data/onix21/codelists/codelist-34.yml +2 -2
  192. data/data/onix21/codelists/codelist-38.yml +1 -1
  193. data/data/onix21/codelists/codelist-39.yml +2 -2
  194. data/data/onix21/codelists/codelist-41.yml +3 -3
  195. data/data/onix21/codelists/codelist-43.yml +1 -1
  196. data/data/onix21/codelists/codelist-44.yml +2 -2
  197. data/data/onix21/codelists/codelist-45.yml +4 -4
  198. data/data/onix21/codelists/codelist-46.yml +3 -3
  199. data/data/onix21/codelists/codelist-48.yml +2 -2
  200. data/data/onix21/codelists/codelist-49.yml +12 -12
  201. data/data/onix21/codelists/codelist-5.yml +3 -3
  202. data/data/onix21/codelists/codelist-51.yml +3 -3
  203. data/data/onix21/codelists/codelist-55.yml +2 -2
  204. data/data/onix21/codelists/codelist-58.yml +10 -10
  205. data/data/onix21/codelists/codelist-59.yml +2 -2
  206. data/data/onix21/codelists/codelist-6.yml +36 -36
  207. data/data/onix21/codelists/codelist-60.yml +1 -1
  208. data/data/onix21/codelists/codelist-62.yml +1 -1
  209. data/data/onix21/codelists/codelist-64.yml +2 -2
  210. data/data/onix21/codelists/codelist-68.yml +2 -2
  211. data/data/onix21/codelists/codelist-69.yml +2 -2
  212. data/data/onix21/codelists/codelist-7.yml +17 -17
  213. data/data/onix21/codelists/codelist-71.yml +2 -2
  214. data/data/onix21/codelists/codelist-73.yml +5 -5
  215. data/data/onix21/codelists/codelist-74.yml +28 -28
  216. data/data/onix21/codelists/codelist-75.yml +1 -1
  217. data/data/onix21/codelists/codelist-76.yml +3 -3
  218. data/data/onix21/codelists/codelist-78.yml +24 -24
  219. data/data/onix21/codelists/codelist-79.yml +6 -6
  220. data/data/onix21/codelists/codelist-8.yml +3 -3
  221. data/data/onix21/codelists/codelist-80.yml +5 -5
  222. data/data/onix21/codelists/codelist-81.yml +4 -4
  223. data/data/onix21/codelists/codelist-83.yml +2 -2
  224. data/data/onix21/codelists/codelist-85.yml +1 -1
  225. data/data/onix21/codelists/codelist-9.yml +3 -3
  226. data/data/onix21/codelists/codelist-90.yml +2 -2
  227. data/data/onix21/codelists/codelist-91.yml +6 -6
  228. data/data/onix21/codelists/codelist-92.yml +1 -1
  229. data/data/onix21/codelists/codelist-93.yml +6 -6
  230. data/data/onix21/codelists/codelist-96.yml +1 -1
  231. data/data/onix21/codelists/codelist-98.yml +2 -2
  232. data/data/onix21/codelists/codelist-99.yml +4 -4
  233. data/doc-src/handlers.rb +32 -2
  234. data/im_onix.gemspec +3 -1
  235. data/lib/onix/addressee.rb +5 -3
  236. data/lib/onix/ancillary_content.rb +7 -0
  237. data/lib/onix/audience.rb +7 -0
  238. data/lib/onix/audience_range.rb +10 -0
  239. data/lib/onix/barcode.rb +6 -0
  240. data/lib/onix/builder.rb +197 -0
  241. data/lib/onix/cited_content.rb +15 -0
  242. data/lib/onix/code.rb +322 -42
  243. data/lib/onix/collateral_detail.rb +9 -13
  244. data/lib/onix/collection.rb +14 -4
  245. data/lib/onix/collection_sequence.rb +3 -3
  246. data/lib/onix/comparison_product_price.rb +17 -0
  247. data/lib/onix/complexity.rb +6 -0
  248. data/lib/onix/content_detail.rb +7 -0
  249. data/lib/onix/content_item.rb +38 -0
  250. data/lib/onix/contributor.rb +56 -34
  251. data/lib/onix/contributor_place.rb +12 -0
  252. data/lib/onix/copyright_statement.rb +8 -0
  253. data/lib/onix/date.rb +107 -56
  254. data/lib/onix/descriptive_detail.rb +98 -49
  255. data/lib/onix/discount.rb +9 -0
  256. data/lib/onix/discount_coded.rb +3 -3
  257. data/lib/onix/entity.rb +22 -37
  258. data/lib/onix/epub_license.rb +8 -0
  259. data/lib/onix/epub_license_expression.rb +7 -0
  260. data/lib/onix/epub_usage_constraint.rb +5 -3
  261. data/lib/onix/epub_usage_limit.rb +2 -2
  262. data/lib/onix/error.rb +2 -0
  263. data/lib/onix/extent.rb +4 -3
  264. data/lib/onix/header.rb +17 -0
  265. data/lib/onix/helper.rb +3 -12
  266. data/lib/onix/identifier.rb +81 -57
  267. data/lib/onix/language.rb +5 -2
  268. data/lib/onix/market.rb +2 -1
  269. data/lib/onix/market_publishing_detail.rb +14 -3
  270. data/lib/onix/measure.rb +7 -0
  271. data/lib/onix/onix21.rb +26 -24
  272. data/lib/onix/onix_message.rb +40 -48
  273. data/lib/onix/page_run.rb +6 -0
  274. data/lib/onix/price.rb +44 -11
  275. data/lib/onix/prize.rb +11 -0
  276. data/lib/onix/product.rb +45 -17
  277. data/lib/onix/product_classification.rb +8 -0
  278. data/lib/onix/product_contact.rb +11 -0
  279. data/lib/onix/product_part.rb +25 -10
  280. data/lib/onix/{product_supplies_extractor.rb → product_supplies_methods.rb} +3 -3
  281. data/lib/onix/product_supply.rb +4 -3
  282. data/lib/onix/professional_affiliation.rb +6 -0
  283. data/lib/onix/publisher_representative.rb +11 -0
  284. data/lib/onix/publishing_detail.rb +22 -9
  285. data/lib/onix/related_material.rb +6 -2
  286. data/lib/onix/related_product.rb +14 -6
  287. data/lib/onix/related_work.rb +5 -3
  288. data/lib/onix/resource_feature.rb +9 -0
  289. data/lib/onix/resource_version.rb +85 -0
  290. data/lib/onix/resource_version_feature.rb +22 -0
  291. data/lib/onix/returns_conditions.rb +8 -0
  292. data/lib/onix/review_rating.rb +7 -0
  293. data/lib/onix/sales_outlet.rb +12 -2
  294. data/lib/onix/sales_restriction.rb +7 -16
  295. data/lib/onix/sales_rights.rb +6 -3
  296. data/lib/onix/sender.rb +5 -5
  297. data/lib/onix/serializer.rb +131 -87
  298. data/lib/onix/subject.rb +11 -6
  299. data/lib/onix/subset.rb +255 -104
  300. data/lib/onix/supplier_own_coding.rb +7 -0
  301. data/lib/onix/supply_contact.rb +9 -0
  302. data/lib/onix/supply_detail.rb +28 -5
  303. data/lib/onix/supporting_resource.rb +10 -113
  304. data/lib/onix/tax.rb +11 -5
  305. data/lib/onix/territory.rb +8 -4
  306. data/lib/onix/text_content.rb +13 -0
  307. data/lib/onix/text_item.rb +12 -0
  308. data/lib/onix/title_detail.rb +4 -3
  309. data/lib/onix/title_element.rb +16 -13
  310. data/lib/onix/website.rb +4 -3
  311. metadata +89 -3
data/lib/onix/subset.rb CHANGED
@@ -1,13 +1,16 @@
1
+ require 'forwardable'
2
+ require 'cgi'
3
+
1
4
  module ONIX
2
5
  class ShortToRef
3
6
  def self.names
4
- @shortnames ||= YAML.load(File.open(File.dirname(__FILE__) + "/../../data/shortnames.yml"))
7
+ @shortnames ||= YAML.load(File.open(File.dirname(__FILE__) + "/../../data/shortnames.yml")).freeze
5
8
  end
6
9
  end
7
10
 
8
11
  class RefToShort
9
12
  def self.names
10
- @refnames ||= ShortToRef.names.invert
13
+ @refnames ||= ShortToRef.names.invert.freeze
11
14
  end
12
15
  end
13
16
 
@@ -22,8 +25,75 @@ module ONIX
22
25
  end
23
26
  end
24
27
 
28
+ # String only code-like class
29
+ class TextAttr
30
+ attr_accessor :code, :human
31
+
32
+ def self.from_code(code)
33
+ obj = self.new
34
+ obj.code = code
35
+ obj.human = code
36
+ obj
37
+ end
38
+ end
39
+
40
+ module Attributes
41
+ # @return [Hash<String,Code>]
42
+ attr_accessor :attributes
43
+
44
+ # @return [Hash<String,String>]
45
+ def serialized_attributes
46
+ if @attributes and @attributes.length > 0
47
+ attrs = {}
48
+ @attributes.each do |k, v|
49
+ attrs[k] = v.code if v
50
+ end
51
+ attrs
52
+ end
53
+ end
54
+
55
+ # @param [String] attr
56
+ # @return [Class]
57
+ def self.attribute_class(attr)
58
+ case attr
59
+ when "sourcename"
60
+ TextAttr
61
+ when "sourcetype"
62
+ RecordSourceType
63
+ when "collationkey"
64
+ TextAttr
65
+ when "dateformat"
66
+ DateFormat
67
+ when "datestamp"
68
+ DateStamp
69
+ when "language"
70
+ LanguageCode
71
+ when "textcase"
72
+ TextCase
73
+ when "textformat"
74
+ TextFormat
75
+ when "textscript"
76
+ ScriptCode
77
+ else
78
+ nil
79
+ end
80
+ end
81
+
82
+ def parse_attributes(attrs)
83
+ @attributes ||= {}
84
+ attrs.each do |k, v|
85
+ attr_klass = Attributes.attribute_class(k.to_s)
86
+ @attributes[k.to_s] = attr_klass ? attr_klass.from_code(v.to_s) : nil
87
+ end
88
+ end
89
+ end
90
+
25
91
  class Subset
92
+ include Attributes
93
+
26
94
  # instanciate Subset form Nokogiri::XML::Element
95
+ # @param [Nokogiri::XML::Element] n
96
+ # @return [Subset]
27
97
  def self.parse(n)
28
98
  o = self.new
29
99
  o.parse(n)
@@ -31,25 +101,25 @@ module ONIX
31
101
  end
32
102
 
33
103
  # parse Nokogiri::XML::Element
104
+ # @param [Nokogiri::XML::Element] n
105
+ # @return [void]
34
106
  def parse(n) end
35
107
 
108
+ # called when tag is not defined
109
+ # @param [String] tag
36
110
  def unsupported(tag)
37
- # raise SubsetUnsupported,tag.name
38
- # puts "SubsetUnsupported: #{self.class}##{tag.name} (#{ShortToRef.names[tag.name]})"
111
+ # raise SubsetUnsupported, [self.class, tag.name]
112
+ # puts "WARN subset tag unsupported #{self.class}##{tag.name} (#{self.class.short_to_ref(tag.name)})"
39
113
  end
40
114
 
41
115
  def tag_match(v)
42
116
  TagNameMatcher.new(v)
43
117
  end
44
-
45
- def self.tag_match(v)
46
- TagNameMatcher.new(v)
47
- end
48
-
49
118
  end
50
119
 
120
+ # for class DSL
51
121
  class ElementParser
52
- attr_accessor :type, :name, :short
122
+ attr_accessor :type, :name, :short, :cardinality, :klass_name
53
123
 
54
124
  def self.inflectors
55
125
  [['ox', 'oxes'],
@@ -96,6 +166,8 @@ module ONIX
96
166
  @parse_lambda = options[:parse_lambda]
97
167
  @serialize_lambda = options[:serialize_lambda]
98
168
  @shortcut = options[:shortcut]
169
+ @cardinality = options[:cardinality]
170
+ @cardinality = nil if @cardinality == 0..n # no need to check if 0..n
99
171
 
100
172
  if options[:klass]
101
173
  @klass_name = options[:klass]
@@ -109,35 +181,20 @@ module ONIX
109
181
  end
110
182
 
111
183
  def parse_lambda(v)
112
- if @parse_lambda
113
- @parse_lambda.call(v)
114
- else
115
- v
116
- end
184
+ @parse_lambda ? @parse_lambda.call(v) : v
117
185
  end
118
186
 
119
187
  def serialize_lambda(v)
120
- if @serialize_lambda
121
- @serialize_lambda.call(v)
122
- else
123
- v
124
- end
188
+ @serialize_lambda ? @serialize_lambda.call(v) : v
125
189
  end
126
190
 
127
191
  def is_array?
128
192
  @array
129
193
  end
130
194
 
131
- def _underscore_name
132
- if @array and @pluralize
133
- pluralize(underscore(@name))
134
- else
135
- underscore(@name)
136
- end
137
- end
138
-
195
+ # @return [String]
139
196
  def underscore_name
140
- @underscore_name ||= _underscore_name
197
+ @underscore_name ||= (@array && @pluralize) ? pluralize(underscore(@name)) : underscore(@name)
141
198
  end
142
199
 
143
200
  def class_name
@@ -172,6 +229,9 @@ module ONIX
172
229
  end
173
230
 
174
231
  class SubsetArray < Array
232
+ # @param [Symbol] k
233
+ # @param [String] p
234
+ # @return [SubsetArray]
175
235
  def human_code_match(k, p)
176
236
  case p
177
237
  when Regexp
@@ -192,6 +252,9 @@ module ONIX
192
252
  end
193
253
  end
194
254
 
255
+ # @param [Symbol] k
256
+ # @param [String] p
257
+ # @return [SubsetArray]
195
258
  def code_match(k, p)
196
259
  case p
197
260
  when Regexp
@@ -205,111 +268,175 @@ module ONIX
205
268
  end
206
269
  end
207
270
 
208
- class SubsetDSL < Subset
209
- def self.scope(name, lambda)
210
- @scopes ||= {}
211
- @scopes[name] = lambda
271
+ class TextWithAttributes < SimpleDelegator
272
+ include Attributes
273
+
274
+ def parse(attrs)
275
+ parse_attributes(attrs)
212
276
  end
277
+ end
213
278
 
214
- def self._ancestor_registered_scopes
215
- els = self.registered_scopes
216
- sup = self
217
- while sup.respond_to?(:registered_scopes)
218
- els.merge!(sup.registered_scopes) if sup.registered_scopes
219
- sup = sup.superclass
279
+ # DSL
280
+ class SubsetDSL < Subset
281
+ class << self
282
+ # convert short name notation to reference
283
+ # @param [String] name
284
+ # @return [String]
285
+ def short_to_ref(name)
286
+ ShortToRef.names[name]
220
287
  end
221
- els
222
- end
223
288
 
224
- def self.ancestor_registered_scopes
225
- @ancestors_registered_scopes ||= _ancestor_registered_scopes
226
- end
289
+ # convert reference name notation to short
290
+ # @param [String] name
291
+ # @return [String]
292
+ def ref_to_short(name)
293
+ RefToShort.names[name]
294
+ end
227
295
 
228
- def self.registered_scopes
229
- @scopes || {}
230
- end
296
+ # infinity constant for cardinality
297
+ def n
298
+ Float::INFINITY
299
+ end
300
+
301
+ # define a scope
302
+ # @param [Symbol] name
303
+ # @param [Lambda] lambda
304
+ # @return [void]
305
+ def scope(name, lambda)
306
+ @scopes ||= {}
307
+ @scopes[name] = lambda
308
+ end
231
309
 
232
- def self.element(name, type, options = {})
233
- @elements ||= {}
234
- @elements[name] = ElementParser.new(name, type, options)
235
- short_name = self.ref_to_short(name)
236
- if short_name
237
- @elements[short_name] = @elements[name].dup
238
- @elements[short_name].short = true
310
+ def registered_scopes
311
+ @scopes || {}
239
312
  end
240
- attr_accessor @elements[name].to_sym
241
- if @elements[name].shortcut
313
+
314
+ def register_scopes(scopes)
315
+ @scopes ||= {}
316
+ @scopes = scopes.merge(@scopes)
317
+ end
318
+
319
+ # define unique element
320
+ # @param [String] name
321
+ # @param [Symbol] type
322
+ # @param [Hash] options
323
+ # @return [void]
324
+ def element(name, type, options = {})
325
+ @elements ||= {}
326
+ @elements[name] = ElementParser.new(name, type, options)
327
+ short_name = self.ref_to_short(name)
328
+ if short_name
329
+ @elements[short_name] = @elements[name].dup
330
+ @elements[short_name].short = true
331
+ end
332
+
333
+ attr_accessor @elements[name].to_sym
334
+
335
+ alias_method "#{@elements[name].underscore_name}_with_attributes".to_sym, @elements[name].to_sym
336
+
242
337
  current_element = @elements[name]
243
- define_method current_element.shortcut do |args = nil|
244
- instance_variable_get(current_element.to_instance)
338
+ define_method current_element.to_sym do |args = nil|
339
+ val = instance_variable_get(current_element.to_instance)
340
+ if val.respond_to?(:__getobj__)
341
+ val.__getobj__
342
+ else
343
+ if val.is_a?(SubsetArray) and val.first and val.first.is_a?(TextWithAttributes)
344
+ val.map { |v| v.respond_to?(:__getobj__) ? v.__getobj__ : v }
345
+ else
346
+ val
347
+ end
348
+ end
245
349
  end
350
+
351
+ if @elements[name].shortcut
352
+ current_element = @elements[name]
353
+ alias_method "#{current_element.shortcut.to_s}_with_attributes".to_sym, "#{@elements[name].underscore_name}_with_attributes".to_sym
354
+ alias_method current_element.shortcut, @elements[name].to_sym
355
+ end
356
+
357
+ @elements[name]
246
358
  end
247
- end
248
359
 
249
- # shortcut for element :array=>true
250
- def self.elements(name, type, options = {})
251
- self.element(name, type, options.merge(:array => true))
252
- end
360
+ # define multiple elements
361
+ # shortcut for element :array=>true
362
+ # @param [String] name
363
+ # @param [Symbol] type
364
+ # @param [Hash] options
365
+ # @return [void]
366
+ def elements(name, type, options = {})
367
+ self.element(name, type, options.merge(:array => true))
368
+ end
253
369
 
254
- def self._ancestors_registered_elements
255
- els = self.registered_elements
256
- sup = self
257
- while sup.respond_to?(:registered_elements)
258
- els.merge!(sup.registered_elements) if sup.registered_elements
259
- sup = sup.superclass
370
+ # registered elements for this subset
371
+ # @return [Hash]
372
+ def registered_elements
373
+ @elements || {}
260
374
  end
261
- els
262
- end
263
375
 
264
- def self.ancestors_registered_elements
265
- @ancestors_registered_elements ||= _ancestors_registered_elements
266
- end
376
+ def register_elements(elements)
377
+ @elements ||= {}
378
+ @elements.merge!(elements)
379
+ end
267
380
 
268
- def self.registered_elements
269
- @elements || {}
381
+ def get_class(name)
382
+ ONIX.const_get(name) if ONIX.const_defined?(name)
383
+ end
384
+
385
+ def inherited(sublass)
386
+ sublass.register_scopes(self.registered_scopes)
387
+ sublass.register_elements(self.registered_elements)
388
+ end
270
389
  end
271
390
 
272
391
  def initialize
273
392
  # initialize plural as Array
274
- self.class.ancestors_registered_elements.each do |k, e|
393
+ self.registered_elements.values.each do |e|
275
394
  if e.is_array?
276
- # register a contextual SubsetArray object
277
- subset_array = SubsetArray.new
278
- subset_klass = self.class.get_class(e.class_name)
279
- if subset_klass.respond_to? :registered_scopes
280
- subset_klass.registered_scopes.each do |n, l|
281
- unless subset_array.respond_to? n.to_s
282
- subset_array.define_singleton_method(n.to_s) do
283
- instance_exec(&l)
284
- end
285
- end
286
- end
287
- end
288
- instance_variable_set(e.to_instance, subset_array)
395
+ register_subset_array(e)
289
396
  end
290
397
  end
291
398
  end
292
399
 
293
- def self.short_to_ref(name)
294
- ShortToRef.names[name]
400
+ def register_subset_array(e)
401
+ # register a contextual SubsetArray object
402
+ subset_array = SubsetArray.new
403
+ subset_klass = self.get_class(e.class_name)
404
+ if subset_klass.respond_to?(:registered_scopes)
405
+ subset_klass.registered_scopes.each do |n, l|
406
+ unless subset_array.respond_to?(n.to_s)
407
+ subset_array.define_singleton_method(n.to_s) do
408
+ instance_exec(&l)
409
+ end
410
+ end
411
+ end
412
+ end
413
+ instance_variable_set(e.to_instance, subset_array)
295
414
  end
296
415
 
297
- def self.ref_to_short(name)
298
- RefToShort.names[name]
416
+ def registered_elements
417
+ self.class.registered_elements
299
418
  end
300
419
 
301
- def self.get_class(name)
302
- ONIX.const_get(name) if ONIX.const_defined? name
420
+ def get_class(name)
421
+ self.class.get_class(name)
303
422
  end
304
423
 
424
+ # @param [Nokogiri::XML::Element] n
425
+ # @return [void]
305
426
  def parse(n)
427
+ parse_attributes(n.attributes)
306
428
  n.elements.each do |t|
307
- name = t.name
308
- e = self.class.ancestors_registered_elements[name]
429
+ e = self.registered_elements[t.name]
309
430
  if e
431
+ primitive = true
310
432
  case e.type
311
433
  when :subset
312
- val = self.class.get_class(e.class_name).parse(t)
434
+ klass = self.get_class(e.class_name)
435
+ unless klass
436
+ raise UnknownElement, e.class_name
437
+ end
438
+ val = klass.parse(t)
439
+ primitive = false
313
440
  when :text
314
441
  val = t.text
315
442
  when :integer
@@ -318,12 +445,41 @@ module ONIX
318
445
  val = t.text.to_f
319
446
  when :bool
320
447
  val = true
448
+ when :date
449
+ fmt = t["dateformat"] || "00"
450
+ begin
451
+ val = ONIX::Helper.to_date(fmt, t.text)
452
+ rescue
453
+ val = t.text
454
+ end
455
+ when :datestamp
456
+ tm = t.text
457
+ datestamp = DateStamp.new
458
+ datestamp.parse(tm)
459
+ val = datestamp
321
460
  when :ignore
322
461
  val = nil
323
462
  else
324
463
  val = t.text
325
464
  end
465
+
326
466
  if val
467
+ if primitive && t.attributes.length > 0
468
+ if t.attributes["textformat"] && t.attributes["textformat"].to_s == "05" # content is XHTML
469
+ xhtml = CGI.unescapeHTML(t.children.map { |x| x.to_s }.join.strip)
470
+ if Nokogiri::XML.parse(xhtml).root # check if val is really XHTML
471
+ val = xhtml
472
+ else
473
+ xhtml = CGI.unescapeHTML(val)
474
+ if Nokogiri::XML.parse(xhtml).root
475
+ val = xhtml
476
+ end
477
+ end
478
+ end
479
+ val = TextWithAttributes.new(val)
480
+ val.parse(t.attributes)
481
+ end
482
+
327
483
  if e.is_array?
328
484
  instance_variable_get(e.to_instance).send(:push, val)
329
485
  else
@@ -335,10 +491,5 @@ module ONIX
335
491
  end
336
492
  end
337
493
  end
338
-
339
- def unsupported(tag)
340
- # raise SubsetUnsupported,tag.name
341
- # puts "SubsetUnsupported: #{self.class}##{tag.name} (#{self.class.short_to_ref(tag.name)})"
342
- end
343
494
  end
344
495
  end
@@ -0,0 +1,7 @@
1
+ module ONIX
2
+ class SupplierOwnCoding < SubsetDSL
3
+ element "SupplierCodeType", :subset, :cardinality => 1
4
+ element "SupplierCodeTypeName", :text, :cardinality => 0..1
5
+ element "SupplierCodeValue", :text, :cardinality => 1
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ module ONIX
2
+ class SupplyContact < SubsetDSL
3
+ element "SupplyContactRole", :subset, :cardinality => 1
4
+ elements "SupplyContactIdentifier", :subset, :cardinality => 0..n
5
+ element "SupplyContactName", :text, :cardinality => 0..1
6
+ element "ContactName", :text, :cardinality => 0..1
7
+ element "EmailAddress", :text, :cardinality => 0..1
8
+ end
9
+ end
@@ -1,14 +1,37 @@
1
+ require 'onix/supply_contact'
2
+ require 'onix/supplier_own_coding'
3
+ require 'onix/returns_conditions'
1
4
  require 'onix/price'
2
5
 
3
6
  module ONIX
4
7
  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
8
+ elements "Supplier", :subset, :cardinality => 1
9
+ elements "SupplyContact", :subset, :cardinality => 0..n
10
+ elements "SupplierOwnCoding", :subset, :cardinality => 0..n
11
+ elements "ReturnsConditions", :subset, :pluralize => false, :cardinality => 0..n
12
+ element "ProductAvailability", :subset, :shortcut => :availability, :cardinality => 1
13
+ elements "SupplyDate", :subset, :cardinality => 0..n
14
+ element "OrderTime", :integer, :cardinality => 0..1
15
+
16
+ # element "NewSupplier", :subset, :cardinality => 0..1
17
+ # elements "Stock", :subset, :cardinality => 0..n
18
+
19
+
20
+ element "PackQuantity", :integer, :cardinality => 0..1
21
+ element "PalletQuantity", :integer, :cardinality => 0..1
22
+ element "OrderQuantityMinimum", :integer, :cardinality => 0..1
23
+
24
+ # element "OrderQuantityMinimum", :integer, :cardinality => 0..1
25
+
26
+
27
+ element "OrderQuantityMultiple", :integer, :cardinality => 0..1
28
+ element "UnpricedItemType", :subset, :cardinality => 0..1
29
+ elements "Price", :subset, :cardinality => 0..n
30
+
31
+ # element "Reissue", :subset, :cardinality => 0..1
10
32
 
11
33
  # @!group Shortcuts
34
+ # @return [Array<Supplier>]
12
35
  def distributors
13
36
  @suppliers.select { |s| s.role.human =~ /Distributor/ }.uniq
14
37
  end
@@ -1,120 +1,15 @@
1
1
  require 'onix/date'
2
+ require 'onix/resource_version'
3
+ require 'onix/resource_feature'
2
4
 
3
5
  module ONIX
4
- class ResourceVersionFeature < SubsetDSL
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
- }
11
-
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") }
15
-
16
- def parse(n)
17
- super
18
-
19
- if @resource_version_feature_type.human == "FileFormat"
20
- @feature_value = SupportingResourceFileFormat.from_code(@feature_value)
21
- end
22
- end
23
- end
24
-
25
- class ResourceVersion < SubsetDSL
26
- element "ResourceForm", :subset, :shortcut => :form
27
- elements "ResourceVersionFeature", :subset, :shortcut => :features
28
- elements "ResourceLink", :text, :shortcut => :links
29
- elements "ContentDate", :subset
30
-
31
- def filename
32
- if @resource_form.human == "DownloadableFile"
33
- @resource_links.first
34
- end
35
- end
36
-
37
- def file_format_feature
38
- @resource_version_features.select { |f| f.type.human == "FileFormat" }.first
39
- end
40
-
41
- def file_format
42
- if ["DownloadableFile", "LinkableResource"].include?(@resource_form.human)
43
- if file_format_feature
44
- file_format_feature.value.human
45
- end
46
- end
47
- end
48
-
49
- def file_mimetype
50
- if ["DownloadableFile", "LinkableResource"].include?(@resource_form.human)
51
- if file_format_feature
52
- file_format_feature.value.mimetype
53
- end
54
- end
55
- end
56
-
57
- def image_width_feature
58
- @resource_version_features.image_pixels_width.first
59
- end
60
-
61
- def image_height_feature
62
- @resource_version_features.image_pixels_height.first
63
- end
64
-
65
- def md5_hash_feature
66
- @resource_version_features.md5_hash.first
67
- end
68
-
69
- def image_width
70
- if self.image_width_feature
71
- self.image_width_feature.value.to_i
72
- end
73
- end
74
-
75
- def image_height
76
- if self.image_height_feature
77
- self.image_height_feature.value.to_i
78
- end
79
- end
80
-
81
- def md5_hash
82
- if self.md5_hash_feature
83
- self.md5_hash_feature.value
84
- end
85
- end
86
-
87
- def last_updated_content_date
88
- @content_dates.last_updated.first
89
- end
90
-
91
- def last_updated
92
- if self.last_updated_content_date
93
- self.last_updated_content_date.date
94
- end
95
- end
96
-
97
- def last_updated_utc
98
- if self.last_updated_content_date and self.last_updated_content_date.date
99
- self.last_updated_content_date.date.to_time.utc.strftime('%Y%m%dT%H%M%S%z')
100
- end
101
- end
102
- end
103
-
104
- class ResourceFeature < SubsetDSL
105
- element "ResourceFeatureType", :subset, :shortcut => :type
106
- element "FeatureValue", :text, :shortcut => :value
107
- elements "FeatureNotes", :text, :shortcut => :notes
108
-
109
- scope :caption, lambda { human_code_match(:resource_feature_type, "Caption") }
110
- end
111
-
112
6
  class SupportingResource < SubsetDSL
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
7
+ element "ResourceContentType", :subset, :shortcut => :type, :cardinality => 1
8
+ element "ContentAudience", :subset, :shortcut => :target_audience, :cardinality => 1..n
9
+ element "Territory", :subset, :cardinality => 0..1
10
+ element "ResourceMode", :subset, :shortcut => :mode, :cardinality => 1
11
+ elements "ResourceFeature", :subset, :shortcut => :features, :cardinality => 0..n
12
+ elements "ResourceVersion", :subset, :shortcut => :versions, :cardinality => 1..n
118
13
 
119
14
  scope :front_cover, lambda { human_code_match(:resource_content_type, "FrontCover") }
120
15
  scope :sample_content, lambda { human_code_match(:resource_content_type, "SampleContent") }
@@ -122,10 +17,12 @@ module ONIX
122
17
  scope :image, lambda { human_code_match(:resource_mode, "Image") }
123
18
  scope :text, lambda { human_code_match(:resource_mode, "Text") }
124
19
 
20
+ # @return [ResourceFeature]
125
21
  def caption_feature
126
22
  self.features.caption.first
127
23
  end
128
24
 
25
+ # @return [String]
129
26
  def caption
130
27
  if self.caption_feature
131
28
  self.caption_feature.value