onix 0.4.0 → 0.4.2
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.
- data/CHANGELOG +8 -0
- data/README.markdown +39 -0
- data/lib/onix.rb +3 -1
- data/lib/onix/apa_product.rb +125 -0
- data/lib/onix/decimal_type.rb +49 -0
- data/lib/onix/header.rb +1 -1
- data/lib/onix/measure.rb +9 -0
- data/lib/onix/product.rb +11 -1
- data/lib/onix/reader.rb +11 -7
- data/lib/onix/writer.rb +2 -5
- data/spec/product_spec.rb +24 -2
- metadata +5 -3
- data/README.rdoc +0 -30
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
v0.4.2 (XXX)
|
2
|
+
- Remove final remnants of REXML code
|
3
|
+
- Minor reordering of elements to match DTD
|
4
|
+
|
5
|
+
v0.4.1 (UNRELEASED)
|
6
|
+
- Added accesses to various product measurements. Height, weight, etc.
|
7
|
+
- Reduced time for an ONIX::Reader class to initialise
|
8
|
+
|
1
9
|
v0.4.0 (28th October 2008)
|
2
10
|
- Major rework: now based on ROXML instead of xml-mapping
|
3
11
|
- Mostly API Compatible
|
data/README.markdown
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
## ONIX
|
2
|
+
|
3
|
+
The ONIX standard is a somewhat verbose XML format that is rapidly becoming the
|
4
|
+
industry standard for electronic data sharing in the book and publishing
|
5
|
+
industries.
|
6
|
+
|
7
|
+
This library provides a slim layer over the format and simplifies both reading
|
8
|
+
and writing ONIX files in your ruby applications.
|
9
|
+
|
10
|
+
This replaces the obsolete rbook-onix gem that was spectacular in its crapness.
|
11
|
+
Let us never speak of it again.
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
gem install onix
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
See files in the examples directory to get started quickly. For further reading
|
20
|
+
view the comments to the following classes:
|
21
|
+
|
22
|
+
* ONIX::Reader - For reading ONIX files
|
23
|
+
* ONIX::Writer - For writing ONIX files
|
24
|
+
|
25
|
+
## Licensing
|
26
|
+
|
27
|
+
This library is distributed under the terms of the MIT License. See the included file for
|
28
|
+
more detail.
|
29
|
+
|
30
|
+
## Contributing
|
31
|
+
|
32
|
+
All suggestions and patches welcome, preferably via a git repository I can pull from.
|
33
|
+
To be honest, I'm not really expecting any, this is a niche library.
|
34
|
+
|
35
|
+
## Further Reading
|
36
|
+
|
37
|
+
- The source: [http://github.com/yob/onix/tree/master](http://github.com/yob/onix/tree/master)
|
38
|
+
- Rubyforge project: [http://rubyforge.org/projects/rbook/](http://rubyforge.org/projects/rbook/)
|
39
|
+
- The official specs [http://www.editeur.org/onix.html](http://www.editeur.org/onix.html)
|
data/lib/onix.rb
CHANGED
@@ -9,6 +9,7 @@ require 'roxml'
|
|
9
9
|
require 'andand'
|
10
10
|
|
11
11
|
# custom xml-mapping node types
|
12
|
+
require File.join(File.dirname(__FILE__), "onix", "decimal_type")
|
12
13
|
require File.join(File.dirname(__FILE__), "onix", "etext_type")
|
13
14
|
require File.join(File.dirname(__FILE__), "onix", "integer_type")
|
14
15
|
require File.join(File.dirname(__FILE__), "onix", "two_digit_type")
|
@@ -33,6 +34,7 @@ require File.join(File.dirname(__FILE__), "onix", "sales_restriction")
|
|
33
34
|
require File.join(File.dirname(__FILE__), "onix", "stock")
|
34
35
|
require File.join(File.dirname(__FILE__), "onix", "price")
|
35
36
|
require File.join(File.dirname(__FILE__), "onix", "supply_detail")
|
37
|
+
require File.join(File.dirname(__FILE__), "onix", "measure")
|
36
38
|
require File.join(File.dirname(__FILE__), "onix", "product")
|
37
39
|
require File.join(File.dirname(__FILE__), "onix", "reader")
|
38
40
|
require File.join(File.dirname(__FILE__), "onix", "writer")
|
@@ -49,7 +51,7 @@ module ONIX
|
|
49
51
|
module Version #:nodoc:
|
50
52
|
Major = 0
|
51
53
|
Minor = 4
|
52
|
-
Tiny =
|
54
|
+
Tiny = 2
|
53
55
|
|
54
56
|
String = [Major, Minor, Tiny].join('.')
|
55
57
|
end
|
data/lib/onix/apa_product.rb
CHANGED
@@ -11,6 +11,18 @@ module ONIX
|
|
11
11
|
delegate :publishing_status, :publishing_status=
|
12
12
|
delegate :publication_date, :publication_date=
|
13
13
|
|
14
|
+
def measurement_system
|
15
|
+
@measurement_system ||= :metric
|
16
|
+
end
|
17
|
+
|
18
|
+
def measurement_system=(value)
|
19
|
+
if value == :metric || value == :imperial
|
20
|
+
@measurement_system = value
|
21
|
+
else
|
22
|
+
raise ArgumentError, "#{value} is not a recognised measurement system"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
14
26
|
# retrieve the current EAN
|
15
27
|
def ean
|
16
28
|
identifier(3).andand.id_value
|
@@ -390,6 +402,98 @@ module ONIX
|
|
390
402
|
price_set(2, num)
|
391
403
|
end
|
392
404
|
|
405
|
+
# retrieve the height of the product
|
406
|
+
#
|
407
|
+
# If APAProduct#measurement_system is metric, these will be in mm, otherwise they
|
408
|
+
# will be in inches.
|
409
|
+
#
|
410
|
+
def height
|
411
|
+
# TODO: auto unit conversion
|
412
|
+
measurement(1).andand.measurement
|
413
|
+
end
|
414
|
+
|
415
|
+
# set the height of the book
|
416
|
+
#
|
417
|
+
# If APAProduct#measurement_system is metric, this should be in mm, otherwise it
|
418
|
+
# will be in inches.
|
419
|
+
#
|
420
|
+
def height=(value)
|
421
|
+
if measurement_system == :metric
|
422
|
+
measurement_set(1,value, "mm")
|
423
|
+
elsif measurement_system == :imperial
|
424
|
+
measurement_set(1,value, "in")
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
# retrieve the width of the product
|
429
|
+
#
|
430
|
+
# If APAProduct#measurement_system is metric, these will be in mm, otherwise they
|
431
|
+
# will be in inches.
|
432
|
+
#
|
433
|
+
def width
|
434
|
+
# TODO: auto unit conversion
|
435
|
+
measurement(2).andand.measurement
|
436
|
+
end
|
437
|
+
|
438
|
+
# set the width of the product
|
439
|
+
#
|
440
|
+
# If APAProduct#measurement_system is metric, this should be in mm, otherwise it
|
441
|
+
# will be in inches.
|
442
|
+
#
|
443
|
+
def width=(value)
|
444
|
+
if measurement_system == :metric
|
445
|
+
measurement_set(2,value, "mm")
|
446
|
+
elsif measurement_system == :imperial
|
447
|
+
measurement_set(2,value, "in")
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
# retrieve the weight of the product
|
452
|
+
#
|
453
|
+
# If APAProduct#measurement_system is metric, these will be in grams, otherwise they
|
454
|
+
# will be in ounces.
|
455
|
+
#
|
456
|
+
def weight
|
457
|
+
# TODO: auto unit conversion
|
458
|
+
measurement(8).andand.measurement
|
459
|
+
end
|
460
|
+
|
461
|
+
# set the weight of the product
|
462
|
+
#
|
463
|
+
# If APAProduct#measurement_system is metric, this should be in grams, otherwise it
|
464
|
+
# will be in ounces.
|
465
|
+
#
|
466
|
+
def weight=(value)
|
467
|
+
if measurement_system == :metric
|
468
|
+
measurement_set(8,value, "gr")
|
469
|
+
elsif measurement_system == :imperial
|
470
|
+
measurement_set(8,value, "oz")
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
# retrieve the thickness of the product
|
475
|
+
#
|
476
|
+
# If APAProduct#measurement_system is metric, these will be in mm, otherwise they
|
477
|
+
# will be in inches.
|
478
|
+
#
|
479
|
+
def thickness
|
480
|
+
# TODO: auto unit conversion
|
481
|
+
measurement(3).andand.measurement
|
482
|
+
end
|
483
|
+
|
484
|
+
# set the thickness of the product
|
485
|
+
#
|
486
|
+
# If APAProduct#measurement_system is metric, this should be in mm, otherwise it
|
487
|
+
# will be in inches.
|
488
|
+
#
|
489
|
+
def thickness=(value)
|
490
|
+
if measurement_system == :metric
|
491
|
+
measurement_set(3,value, "mm")
|
492
|
+
elsif measurement_system == :imperial
|
493
|
+
measurement_set(3,value, "in")
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
393
497
|
private
|
394
498
|
|
395
499
|
# add a new subject to this product
|
@@ -431,6 +535,27 @@ module ONIX
|
|
431
535
|
isbn_id.id_value = value
|
432
536
|
end
|
433
537
|
|
538
|
+
# retrieve the value of a particular measurement
|
539
|
+
def measurement(type)
|
540
|
+
product.measurements.find { |m| m.measure_type_code == type }
|
541
|
+
end
|
542
|
+
|
543
|
+
# set the value of a particular measurement
|
544
|
+
def measurement_set(type, value, unit)
|
545
|
+
measure = measurement(type)
|
546
|
+
|
547
|
+
# create a new isbn record if we need to
|
548
|
+
if measure.nil?
|
549
|
+
measure = ONIX::Measure.new
|
550
|
+
measure.measure_type_code = type
|
551
|
+
product.measurements << measure
|
552
|
+
end
|
553
|
+
|
554
|
+
# store the new value
|
555
|
+
measure.measurement = value
|
556
|
+
measure.measure_unit_code = unit.to_s
|
557
|
+
end
|
558
|
+
|
434
559
|
# retrieve the value of a particular media file
|
435
560
|
def media_file(type)
|
436
561
|
product.media_files.find { |m| m.media_file_type_code == type }
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
|
3
|
+
module ONIX
|
4
|
+
|
5
|
+
class DecimalType < ROXML::XMLRef # ::nodoc::
|
6
|
+
attr_reader :cdata, :content
|
7
|
+
|
8
|
+
def initialize(accessor, args, &block)
|
9
|
+
super(accessor, args, &block)
|
10
|
+
@content = args.content?
|
11
|
+
@cdata = args.cdata?
|
12
|
+
end
|
13
|
+
|
14
|
+
# Updates the text in the given _xml_ block to
|
15
|
+
# the _value_ provided.
|
16
|
+
def update_xml(xml, value)
|
17
|
+
parent = wrap(xml)
|
18
|
+
if value.kind_of?(BigDecimal)
|
19
|
+
value = value.to_s("F")
|
20
|
+
else
|
21
|
+
value = value.to_s
|
22
|
+
end
|
23
|
+
add(parent.child_add(LibXML::XML::Node.new_element(name)), value)
|
24
|
+
xml
|
25
|
+
end
|
26
|
+
|
27
|
+
def value(xml)
|
28
|
+
if content
|
29
|
+
value = BigDecimal.new(xml.content)
|
30
|
+
else
|
31
|
+
child = xml.search(name).first
|
32
|
+
value = BigDecimal.new(child.content) if child
|
33
|
+
end
|
34
|
+
block ? block.call(value) : value
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def add(dest, value)
|
40
|
+
if cdata
|
41
|
+
dest.child_add(LibXML::XML::Node.new_cdata(value.to_utf))
|
42
|
+
else
|
43
|
+
dest.content = value.to_utf
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
ROXML::TypeRegistry.register(:decimal, ONIX::DecimalType)
|
data/lib/onix/header.rb
CHANGED
@@ -4,11 +4,11 @@ module ONIX
|
|
4
4
|
|
5
5
|
xml_name "Header"
|
6
6
|
|
7
|
-
xml_accessor :from_person, :etext, :from => "FromPerson"
|
8
7
|
xml_accessor :from_ean_number, :etext, :from => "FromEANNumber"
|
9
8
|
xml_accessor :from_san, :etext, :from => "FromSAN"
|
10
9
|
xml_accessor :sender_identifiers, [ONIX::SenderIdentifier], :from => "SenderIdentifier"
|
11
10
|
xml_accessor :from_company, :etext, :from => "FromCompany"
|
11
|
+
xml_accessor :from_person, :etext, :from => "FromPerson"
|
12
12
|
xml_accessor :from_email, :etext, :from => "FromEmail"
|
13
13
|
xml_accessor :to_ean_number, :etext, :from => "ToEANNumber"
|
14
14
|
xml_accessor :to_san, :etext, :from => "ToSAN"
|
data/lib/onix/measure.rb
ADDED
data/lib/onix/product.rb
CHANGED
@@ -11,8 +11,8 @@ module ONIX
|
|
11
11
|
xml_accessor :series, :from => "Series"
|
12
12
|
xml_accessor :edition_number, :integer, :from => "EditionNumber"
|
13
13
|
xml_accessor :titles, [ONIX::Title], :from => "Title"
|
14
|
-
xml_accessor :websites, [ONIX::Website], :from => "Website"
|
15
14
|
xml_accessor :contributors, [ONIX::Contributor], :from => "Contributor"
|
15
|
+
xml_accessor :websites, [ONIX::Website], :from => "Website"
|
16
16
|
xml_accessor :number_of_pages, :integer, :from => "NumberOfPages"
|
17
17
|
xml_accessor :bic_main_subject, :from => "BICMainSubject"
|
18
18
|
xml_accessor :subjects, [ONIX::Subject], :from => "Subject"
|
@@ -24,7 +24,17 @@ module ONIX
|
|
24
24
|
xml_accessor :publication_date, :yyyymmdd, :from => "PublicationDate"
|
25
25
|
xml_accessor :year_first_published, :integer, :from => "YearFirstPublished"
|
26
26
|
xml_accessor :sales_restrictions, [ONIX::SalesRestriction], :from => "SalesRestriction"
|
27
|
+
xml_accessor :measurements, [ONIX::Measure], :from => "Measure"
|
27
28
|
xml_accessor :supply_details, [ONIX::SupplyDetail], :from => "SupplyDetail"
|
28
29
|
|
30
|
+
# some deprecated attributes. Read only
|
31
|
+
# - See the measures array for the current way of specifying
|
32
|
+
# various measurements of the product
|
33
|
+
xml_reader :height, :decimal, :from => "Height"
|
34
|
+
xml_reader :width, :decimal, :from => "Width"
|
35
|
+
xml_reader :thickness, :decimal, :from => "Thickness"
|
36
|
+
xml_reader :weight, :decimal, :from => "Weight"
|
37
|
+
xml_reader :dimensions, :etext, :from => "Dimensions"
|
38
|
+
|
29
39
|
end
|
30
40
|
end
|
data/lib/onix/reader.rb
CHANGED
@@ -68,18 +68,22 @@ module ONIX
|
|
68
68
|
@product_klass = product_klass
|
69
69
|
|
70
70
|
# create a sized queue to store each product read from the file
|
71
|
+
# We use a separate thread to read products from the source file.
|
72
|
+
# This queue is a thread-safe way to transfer products from that
|
73
|
+
# thread back into the main one.
|
71
74
|
@queue = SizedQueue.new(100)
|
72
75
|
|
73
|
-
# launch a reader thread
|
74
|
-
# product in the queue
|
76
|
+
# launch a reader thread
|
75
77
|
Thread.abort_on_exception = true
|
76
78
|
Thread.new { read_input }
|
77
79
|
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
|
80
|
+
# don't return from the constructor until the reading thread
|
81
|
+
# has spun up and put at least one item into the queue. If
|
82
|
+
# it finds no Products in the file, it queues a nil, so we
|
83
|
+
# shouldn't get stuck here indefinitely
|
84
|
+
while @queue.size == 0
|
85
|
+
sleep 0.05
|
86
|
+
end
|
83
87
|
end
|
84
88
|
|
85
89
|
# Iterate over all the products in an ONIX file
|
data/lib/onix/writer.rb
CHANGED
@@ -73,11 +73,8 @@ module ONIX
|
|
73
73
|
private
|
74
74
|
|
75
75
|
def start_document
|
76
|
-
|
77
|
-
|
78
|
-
decl.encoding = "utf-8"
|
79
|
-
@output.write(decl.to_s+"\n")
|
80
|
-
@output.write(doctype.to_s+"\n")
|
76
|
+
@output.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
|
77
|
+
@output.write("<!DOCTYPE ONIXMessage SYSTEM \"#{DOCTYPE}\">\n")
|
81
78
|
@output.write("<ONIXMessage>\n")
|
82
79
|
@output.write(@header.to_xml.to_s)
|
83
80
|
@output.write("\n")
|
data/spec/product_spec.rb
CHANGED
@@ -8,8 +8,8 @@ require 'date'
|
|
8
8
|
context "ONIX::Product" do
|
9
9
|
|
10
10
|
before(:each) do
|
11
|
-
data_path = File.join(File.dirname(__FILE__),"..","data")
|
12
|
-
file1 = File.join(data_path, "product.xml")
|
11
|
+
@data_path = File.join(File.dirname(__FILE__),"..","data")
|
12
|
+
file1 = File.join(@data_path, "product.xml")
|
13
13
|
@doc = LibXML::XML::Document.file(file1)
|
14
14
|
@product_node = @doc.root
|
15
15
|
end
|
@@ -26,6 +26,13 @@ context "ONIX::Product" do
|
|
26
26
|
product.publishing_status.should eql(4)
|
27
27
|
product.publication_date.should eql(Date.civil(1998,9,1))
|
28
28
|
product.year_first_published.should eql(1998)
|
29
|
+
|
30
|
+
# including ye olde, deprecated ones
|
31
|
+
product.height.should eql(100)
|
32
|
+
product.width.should eql(BigDecimal.new("200.5"))
|
33
|
+
product.weight.should eql(300)
|
34
|
+
product.thickness.should eql(300)
|
35
|
+
product.dimensions.should eql("100x200")
|
29
36
|
end
|
30
37
|
|
31
38
|
specify "should provide read access to product IDs" do
|
@@ -43,6 +50,11 @@ context "ONIX::Product" do
|
|
43
50
|
product.subjects.size.should eql(1)
|
44
51
|
end
|
45
52
|
|
53
|
+
specify "should provide read access to measurements" do
|
54
|
+
product = ONIX::Product.parse(@product_node.to_s)
|
55
|
+
product.measurements.size.should eql(1)
|
56
|
+
end
|
57
|
+
|
46
58
|
specify "should provide write access to first level attibutes" do
|
47
59
|
product = ONIX::Product.new
|
48
60
|
|
@@ -72,4 +84,14 @@ context "ONIX::Product" do
|
|
72
84
|
product.year_first_published = 1998
|
73
85
|
product.year_first_published.should eql(1998)
|
74
86
|
end
|
87
|
+
|
88
|
+
specify "should correctly parse files that have non-standard entties"
|
89
|
+
=begin
|
90
|
+
do
|
91
|
+
file = File.join(@data_path, "extra_entities.xml")
|
92
|
+
product = ONIX::Product.parse(File.read(file))
|
93
|
+
|
94
|
+
product.titles.first.title_text.should eql("Ipod® & Itunes® for Dummies®, 4th Edition")
|
95
|
+
end
|
96
|
+
=end
|
75
97
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: onix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Healy
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-11-01 00:00:00 +11:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -78,8 +78,10 @@ files:
|
|
78
78
|
- lib/onix/two_digit_type.rb
|
79
79
|
- lib/onix/writer.rb
|
80
80
|
- lib/onix/etext_type.rb
|
81
|
+
- lib/onix/measure.rb
|
82
|
+
- lib/onix/decimal_type.rb
|
81
83
|
- lib/onix.rb
|
82
|
-
- README.
|
84
|
+
- README.markdown
|
83
85
|
- TODO
|
84
86
|
- CHANGELOG
|
85
87
|
has_rdoc: true
|
data/README.rdoc
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
== ONIX
|
2
|
-
|
3
|
-
The ONIX standard is a somewhat verbose XML format that is rapidly becoming the
|
4
|
-
industry standard for electronic data sharing in the book and publishing
|
5
|
-
industries.
|
6
|
-
|
7
|
-
This library provides a slim layer over the format and simplifies both reading
|
8
|
-
and writing ONIX files in your ruby applications.
|
9
|
-
|
10
|
-
== Installation
|
11
|
-
|
12
|
-
gem install onix
|
13
|
-
|
14
|
-
== Usage
|
15
|
-
|
16
|
-
See files in the examples directory to get started quickly. For further reading
|
17
|
-
view the comments to the following classes:
|
18
|
-
|
19
|
-
* ONIX::Reader - For reading ONIX files
|
20
|
-
* ONIX::Writer - For writing ONIX files
|
21
|
-
|
22
|
-
== Contributing
|
23
|
-
|
24
|
-
All suggestions and patches welcome, preferably via a git repository I can pull from.
|
25
|
-
|
26
|
-
== Further Reading
|
27
|
-
|
28
|
-
- The source: (http://github.com/yob/onix/tree/master)[http://github.com/yob/onix/tree/master]
|
29
|
-
- Rubyforge project: (http://rubyforge.org/projects/rbook/)[http://rubyforge.org/projects/rbook/]
|
30
|
-
- The official specs (http://www.editeur.org/onix.html)[http://www.editeur.org/onix.html]
|