rbook 0.4.3 → 0.5

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 (87) hide show
  1. data/Rakefile +13 -176
  2. metadata +57 -117
  3. data/COPYING +0 -340
  4. data/LICENSE +0 -13
  5. data/README +0 -17
  6. data/examples/gbip.rb +0 -12
  7. data/examples/onix/stream_reader.rb +0 -13
  8. data/examples/pacstream.rb +0 -13
  9. data/examples/titlepage.rb +0 -14
  10. data/examples/titlepage_with_proxy.rb +0 -14
  11. data/examples/titlepage_www.rb +0 -18
  12. data/examples/www/find_all.rb +0 -23
  13. data/examples/www/find_cover_from_amazon.rb +0 -16
  14. data/examples/www/find_url_from_rainbow.rb +0 -12
  15. data/examples/www/list.rb +0 -13
  16. data/lib/rbook/bisac.rb +0 -31
  17. data/lib/rbook/bisac/message.rb +0 -99
  18. data/lib/rbook/bisac/po.rb +0 -97
  19. data/lib/rbook/bisac/po_line_item.rb +0 -33
  20. data/lib/rbook/bisac/product.rb +0 -176
  21. data/lib/rbook/errors.rb +0 -8
  22. data/lib/rbook/gbip.rb +0 -21
  23. data/lib/rbook/gbip/pos.rb +0 -118
  24. data/lib/rbook/gbip/title.rb +0 -36
  25. data/lib/rbook/gbip/warehouse.rb +0 -27
  26. data/lib/rbook/isbn.rb +0 -255
  27. data/lib/rbook/onix.rb +0 -70
  28. data/lib/rbook/onix/contributor.rb +0 -60
  29. data/lib/rbook/onix/lists.rb +0 -2
  30. data/lib/rbook/onix/lists/contributor_role.rb +0 -10
  31. data/lib/rbook/onix/lists/product_form.rb +0 -100
  32. data/lib/rbook/onix/message.rb +0 -112
  33. data/lib/rbook/onix/product.rb +0 -189
  34. data/lib/rbook/onix/sales_restriction.rb +0 -51
  35. data/lib/rbook/onix/stream_reader.rb +0 -120
  36. data/lib/rbook/onix/stream_writer.rb +0 -40
  37. data/lib/rbook/onix/supply_detail.rb +0 -68
  38. data/lib/rbook/onix/xchar.rb +0 -98
  39. data/lib/rbook/pacstream.rb +0 -64
  40. data/lib/rbook/titlepage.rb +0 -37
  41. data/lib/rbook/titlepage/client.rb +0 -126
  42. data/lib/rbook/titlepage/titlepage_driver.rb +0 -137
  43. data/lib/rbook/titlepage/titlepage_utils.rb +0 -379
  44. data/lib/rbook/titlepage/wwwclient.rb +0 -96
  45. data/lib/rbook/www.rb +0 -172
  46. data/lib/rbook/www/aau_scraper.rb +0 -76
  47. data/lib/rbook/www/amazon_uk_scraper.rb +0 -44
  48. data/lib/rbook/www/ban_scraper.rb +0 -62
  49. data/lib/rbook/www/base.rb +0 -87
  50. data/lib/rbook/www/harper_au_scraper.rb +0 -56
  51. data/lib/rbook/www/harper_us_scraper.rb +0 -55
  52. data/lib/rbook/www/hha_scraper.rb +0 -50
  53. data/lib/rbook/www/macmillan_scraper.rb +0 -62
  54. data/lib/rbook/www/orbis_scraper.rb +0 -48
  55. data/lib/rbook/www/oup_scraper.rb +0 -64
  56. data/lib/rbook/www/paulist_scraper.rb +0 -53
  57. data/lib/rbook/www/pearson_au_scraper.rb +0 -52
  58. data/lib/rbook/www/penguin_scraper.rb +0 -45
  59. data/lib/rbook/www/random_au_scraper.rb +0 -90
  60. data/lib/rbook/www/random_us_scraper.rb +0 -59
  61. data/lib/rbook/www/sas_scraper.rb +0 -54
  62. data/lib/rbook/www/unireps_scraper.rb +0 -58
  63. data/lib/rbook/www/wiley_us_scraper.rb +0 -54
  64. data/test/data/abingdon.xml +0 -38931
  65. data/test/data/augsburg.xml +0 -39009
  66. data/test/data/bisac_po.txt +0 -112
  67. data/test/data/chalice.xml +0 -10851
  68. data/test/data/eerdsman.xml +0 -36942
  69. data/test/data/invalid_no_product.xml +0 -9
  70. data/test/data/not_xml.csv +0 -1
  71. data/test/data/single_product.xml +0 -50
  72. data/test/data/valid_bisac.txt +0 -213
  73. data/test/data/xml_not_onix.xml +0 -7
  74. data/test/mocks/titlepage_driver.rb +0 -111
  75. data/test/unit/bisac/bisac_test.rb +0 -96
  76. data/test/unit/bisac/po_line_item_test.rb +0 -38
  77. data/test/unit/bisac/po_test.rb +0 -82
  78. data/test/unit/isbn_test.rb +0 -153
  79. data/test/unit/onix/contributor_test.rb +0 -50
  80. data/test/unit/onix/message_test.rb +0 -119
  81. data/test/unit/onix/product_test.rb +0 -101
  82. data/test/unit/onix/sales_restriction_test.rb +0 -48
  83. data/test/unit/onix/stream_reader_test.rb +0 -22
  84. data/test/unit/onix/stream_writer_test.rb +0 -32
  85. data/test/unit/onix/supply_detail_test.rb +0 -53
  86. data/test/unit/onix/xchar_test.rb +0 -37
  87. data/test/unit/titlepage_test.rb +0 -140
@@ -1,51 +0,0 @@
1
- require 'rexml/document'
2
- require 'rubygems'
3
-
4
- module RBook
5
- module Onix
6
-
7
- class SalesRestriction
8
- attr_accessor :type, :detail
9
-
10
- # Attempts to create a contributor object using the supplied xml element
11
- def SalesRestriction.load_from_element(element)
12
- raise ArgumentError, 'load_from_element expects a REXML element object' unless element.class == REXML::Element
13
-
14
- if REXML::XPath.first(element, '//SalesRestriction').nil?
15
- raise LoadError, 'supplied REXML document object does not appear contain a valid SalesRestriction fragment'
16
- end
17
-
18
- restriction = SalesRestriction.new
19
-
20
- tmp = REXML::XPath.first(element, '//SalesRestriction/SalesRestrictionType')
21
- restriction.type = tmp.text if tmp != nil
22
-
23
- tmp = REXML::XPath.first(element, '//SalesRestriction/SalesRestrictionDetail')
24
- restriction.detail = tmp.text if tmp != nil
25
-
26
- return restriction
27
-
28
- end
29
-
30
- # Return an xml element representing this contributor
31
- def to_element
32
- raise 'SalesRestriction must have a type to create an element' if self.type.nil?
33
- raise 'Contributor must have a detail to create an element' if self.detail.nil?
34
-
35
- restriction = REXML::Element.new('SalesRestriction')
36
- restriction.add_element('SalesRestrictionType').text = self.type.to_xs
37
- restriction.add_element('SalesRestrictionDetail').text = self.detail.to_xs
38
-
39
- return restriction
40
- end
41
-
42
- # Return an XML string representing this contributor
43
- def to_s
44
- tmp = to_element
45
- output = ''
46
- tmp.write(output, 0)
47
- return output
48
- end
49
- end
50
- end
51
- end
@@ -1,120 +0,0 @@
1
- require 'rexml/document'
2
- require 'thread'
3
-
4
- module RBook
5
- module Onix
6
-
7
- # a utility class for the ONIX Stream Reader. See RBook::ONIX::StreamReader for
8
- # basic usage instructions.
9
- class Listener
10
-
11
- def initialize(queue)
12
- @queue = queue
13
- @in_product = false
14
- end
15
-
16
- def doctype(name, pub_sys, long_name, uri)
17
- end
18
-
19
- def tag_start(name, attrs)
20
- case name
21
- when "Product"
22
- # A new product tag has been read, so start
23
- # building a new product to add to the queue
24
- @in_product = true
25
- @product_fragment = "<Product>"
26
- else
27
- @product_fragment << "<#{name}>" if @in_product
28
- end
29
- end
30
-
31
- def text(text)
32
- @product_fragment << text if @in_product
33
- end
34
-
35
- def tag_end(name)
36
- case name
37
- when "ONIXMessage"
38
- # the ONIXMessage tag indicates the end of the file, so add
39
- # nil to the queue to let the iterating thread know reading
40
- # is finished
41
- @queue.push(nil)
42
- when "Product"
43
- # A product tag is finished, so add it to the queue
44
- @product_fragment << "</Product>"
45
- begin
46
- doc = REXML::Document.new(@product_fragment)
47
- unless doc.root.nil?
48
- product = RBook::Onix::Product.load_from_element(doc.root)
49
- @queue.push(product) unless product.nil?
50
- end
51
- rescue
52
- # error occurred while building the product from an XML fragment
53
- end
54
- @in_product = false
55
- else
56
- @product_fragment << "</#{name}>" if @in_product
57
- end
58
- end
59
-
60
- def xmldecl(version, encoding, standalone)
61
- # do nothing
62
- end
63
-
64
- def method_missing
65
- # do nothing
66
- end
67
- end
68
-
69
- # A stream reader for ONIX files. Using a stream reader is preferred for
70
- # large XML files as the file is processed in stages, removing the need
71
- # to store the entire thing in memory at once.
72
- #
73
- # This class provides forward only iteration over a single ONIX file,
74
- # returning a RBook::ONIX::Product object for each product encountered.
75
- #
76
- # = Basic usage
77
- # require 'rbook/onix'
78
- # reader = RBook::ONIX::StreamReader.new("some_onix_file.xml")
79
- # reader.each do |product|
80
- # puts product.inspect
81
- # end
82
- class StreamReader
83
-
84
- # creates a new stream reader to read the specified file.
85
- # file can be specified as a String or File object
86
- def initialize(input)
87
- if input.class == String
88
- @input = File.new(input)
89
- elsif input.class == File
90
- @input = input
91
- else
92
- throw "Unable to read from path or file"
93
- end
94
- # create a sized queue to store each product read from the file
95
- @queue = SizedQueue.new(100)
96
-
97
- # launch a reader thread to process the file and store each
98
- # product in the queue
99
- Thread.new do
100
- producer = Listener.new(@queue)
101
- REXML::Document.parse_stream(@input, producer)
102
- end
103
- end
104
-
105
- # iterate over the file and return a product file to a block.
106
- #
107
- # reader = RBook::ONIX::StreamReader.new("some_onix_file.xml")
108
- # reader.each do |product|
109
- # puts product.inspect
110
- # end
111
- def each
112
- obj = @queue.pop
113
- while !obj.nil?
114
- yield obj
115
- obj = @queue.pop
116
- end
117
- end
118
- end
119
- end
120
- end
@@ -1,40 +0,0 @@
1
- require 'rexml/document'
2
-
3
- module RBook
4
- module Onix
5
-
6
- class StreamWriter
7
-
8
- # Default constructor.
9
- def initialize(output, msg)
10
- raise ArgumentError, 'msg must be an RBook::Onix::Message object' unless msg.class == RBook::Onix::Message
11
- @output = output
12
- @msg = msg
13
- end
14
-
15
- def start_document(encoding = nil)
16
- decl = REXML::XMLDecl.new
17
- doctype = REXML::DocType.new('ONIXMessage', "SYSTEM \"#{RBook::Onix::Message::ONIX_DTD_URL}\"")
18
- if encoding
19
- decl.encoding = encoding
20
- else
21
- decl.encoding = "UTF-8"
22
- end
23
- @output.write(decl.to_s+"\n")
24
- @output.write(doctype.to_s+"\n")
25
- @output.write("<ONIXMessage>\n")
26
- @output.write(@msg.header.to_s)
27
- end
28
-
29
- def << (product)
30
- @output.write(product.to_s)
31
- end
32
-
33
- def end_document
34
- @output.write("</ONIXMessage>\n")
35
- end
36
-
37
- end
38
-
39
- end
40
- end
@@ -1,68 +0,0 @@
1
- require 'rexml/document'
2
- require 'bigdecimal'
3
- require 'rubygems'
4
-
5
- module RBook
6
- module Onix
7
-
8
- class SupplyDetail
9
- attr_accessor :supplier_name, :availability_code, :intermediary_availability_code, :price
10
-
11
- # Attempts to create a contributor object using the supplied xml element
12
- def self.load_from_element(element)
13
- raise ArgumentError, 'load_from_element expects a REXML element object' unless element.class == REXML::Element
14
-
15
- if REXML::XPath.first(element, '//SupplyDetail').nil?
16
- raise LoadError, 'supplied REXML document object does not appear contain a valid SupplyDetail fragment'
17
- end
18
-
19
- supply_detail = SupplyDetail.new
20
-
21
- tmp = REXML::XPath.first(element, '//SupplyDetail/SupplierName')
22
- supply_detail.supplier_name = tmp.text if tmp != nil
23
-
24
- tmp = REXML::XPath.first(element, '//SupplyDetail/AvailabilityCode')
25
- supply_detail.availability_code = tmp.text if tmp != nil
26
-
27
- tmp = REXML::XPath.first(element, '//SupplyDetail/IntermediaryAvailabilityCode')
28
- supply_detail.intermediary_availability_code = tmp.text if tmp != nil
29
-
30
- tmp = REXML::XPath.first(element, '//SupplyDetail/Price/PriceAmount')
31
- supply_detail.price = BigDecimal(tmp.text) if tmp != nil
32
-
33
- return supply_detail
34
-
35
- end
36
-
37
- # Return an xml element representing this contributor
38
- def to_element
39
- raise 'SupplyDetail must have a supplier name to create an element' if self.supplier_name.nil?
40
- raise 'SupplyDetail must have a availability code to create an element' if self.availability_code.nil?
41
-
42
- supply_detail = REXML::Element.new('SupplyDetail')
43
- supply_detail.add_element('SupplierName').text = self.supplier_name.to_xs
44
- supply_detail.add_element('AvailabilityCode').text = self.availability_code.to_xs unless self.availability_code.nil?
45
- supply_detail.add_element('IntermediaryAvailabilityCode').text = self.intermediary_availability_code.to_xs unless self.intermediary_availability_code.nil?
46
- unless self.price.nil?
47
- tmp = REXML::Element.new('Price')
48
- if self.price.kind_of?(BigDecimal)
49
- tmp.add_element('PriceAmount').text = self.price.to_s("F")
50
- else
51
- tmp.add_element('PriceAmount').text = self.price.to_s
52
- end
53
- supply_detail.add_element(tmp)
54
- end
55
-
56
- return supply_detail
57
- end
58
-
59
- # Return an XML string representing this contributor
60
- def to_s
61
- tmp = to_element
62
- output = ''
63
- tmp.write(output, 0)
64
- return output
65
- end
66
- end
67
- end
68
- end
@@ -1,98 +0,0 @@
1
- # sourced from http://www.intertwingly.net/blog/2005/09/28/XML-Cleansing
2
-
3
- module XChar
4
- # http://intertwingly.net/stories/2004/04/14/i18n.html#CleaningWindows
5
- CP1252 = {
6
- 128 => 8364, # euro sign
7
- 130 => 8218, # single low-9 quotation mark
8
- 131 => 402, # latin small letter f with hook
9
- 132 => 8222, # double low-9 quotation mark
10
- 133 => 8230, # horizontal ellipsis
11
- 134 => 8224, # dagger
12
- 135 => 8225, # double dagger
13
- 136 => 710, # modifier letter circumflex accent
14
- 137 => 8240, # per mille sign
15
- 138 => 352, # latin capital letter s with caron
16
- 139 => 8249, # single left-pointing angle quotation mark
17
- 140 => 338, # latin capital ligature oe
18
- 142 => 381, # latin capital letter z with caron
19
- 145 => 8216, # left single quotation mark
20
- 146 => 8217, # right single quotation mark
21
- 147 => 8220, # left double quotation mark
22
- 148 => 8221, # right double quotation mark
23
- 149 => 8226, # bullet
24
- 150 => 8211, # en dash
25
- 151 => 8212, # em dash
26
- 152 => 732, # small tilde
27
- 153 => 8482, # trade mark sign
28
- 154 => 353, # latin small letter s with caron
29
- 155 => 8250, # single right-pointing angle quotation mark
30
- 156 => 339, # latin small ligature oe
31
- 158 => 382, # latin small letter z with caron
32
- 159 => 376} # latin capital letter y with diaeresis
33
-
34
- # http://www.w3.org/TR/REC-xml/#dt-chardata
35
- PREDEFINED = {
36
- 38 => '&amp;', # ampersand
37
- 60 => '&lt;', # left angle bracket
38
- 62 => '&gt;'} # right angle bracket
39
-
40
- # http://www.w3.org/TR/REC-xml/#charsets
41
- VALID = [[0x9, 0xA, 0xD], (0x20..0xD7FF),
42
- (0xE000..0xFFFD), (0x10000..0x10FFFF)]
43
- end
44
-
45
- class Fixnum
46
- # xml escaped version of chr
47
- def xchr
48
- n = XChar::CP1252[self] || self
49
- n = 42 unless XChar::VALID.find {|range| range.include? n}
50
- XChar::PREDEFINED[n] or (n<128 ? n.chr : "&##{n};")
51
- end
52
- end
53
-
54
- class String
55
- # xml escaped version of to_s
56
- def to_xs
57
- unpack('U*').map {|n| n.xchr}.join # ASCII, UTF-8
58
- rescue
59
- unpack('C*').map {|n| n.xchr}.join # ISO-8859-1, WIN-1252
60
- end
61
- end
62
-
63
- =begin
64
- require 'test/unit'
65
-
66
- class TestXmlEscaping < Test::Unit::TestCase
67
- def test_ascii
68
- assert_equal 'abc', 'abc'.to_xs
69
- end
70
-
71
- def test_predefined
72
- assert_equal '&amp;', '&'.to_xs # ampersand
73
- assert_equal '&lt;', '<'.to_xs # left angle bracket
74
- assert_equal '&gt;', '>'.to_xs # right angle bracket
75
- end
76
-
77
- def test_invalid
78
- assert_equal '*', "\x00".to_xs # null
79
- assert_equal '*', "\x0C".to_xs # form feed
80
- assert_equal '*', "\xEF\xBF\xBF".to_xs # U+FFFF
81
- end
82
-
83
- def test_iso_8859_1
84
- assert_equal '&#231;', "\xE7".to_xs # small c cedilla
85
- assert_equal '&#169;', "\xA9".to_xs # copyright symbol
86
- end
87
-
88
- def test_win_1252
89
- assert_equal '&#8217;', "\x92".to_xs # smart quote
90
- assert_equal '&#8364;', "\x80".to_xs # euro
91
- end
92
-
93
- def test_utf8
94
- assert_equal '&#8217;', "\xE2\x80\x99".to_xs # right single quote
95
- assert_equal '&#169;', "\xC2\xA9".to_xs # copy
96
- end
97
- end
98
- =end
@@ -1,64 +0,0 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__) + "/../")
2
-
3
- require 'net/ftp'
4
- require 'tempfile'
5
-
6
- module RBook
7
-
8
- # Ruby class for sending and retrieving electronic orders
9
- # via pacstream, a service run by the ECN GRoup
10
- # (http://www.ecngroup.com.au/)
11
- #
12
- # = Basic Usage
13
- #
14
- # RBook::Pacstream.get(:orders, :username => "myusername", :password => "mypass") do |order|
15
- # puts order
16
- # end
17
- class Pacstream
18
-
19
- FILE_EXTENSIONS = { :orders => "ORD" }
20
-
21
- # Iterate over each order waiting on the pacstream server, returning
22
- # each file as a string
23
- #
24
- # RBook::Pacstream.get(:orders, :username => "myusername", :password => "mypass") do |order|
25
- # puts order
26
- # end
27
- def self.get(type = :orders, *args, &block)
28
- if args[0][:username].nil? && args[0][:password].nil?
29
- raise ArgumentError, 'username and password must be specified'
30
- end
31
-
32
- unless FILE_EXTENSIONS.include?(type)
33
- raise ArgumentError, 'unrecognised type'
34
- end
35
-
36
- server = args[0][:servername] || "pacstream.tedis.com.au"
37
-
38
- begin
39
- transaction_complete = false
40
- Net::FTP.open(server) do |ftp|
41
-
42
- file_regexp = Regexp.new(".*\.#{FILE_EXTENSIONS[type]}$", Regexp::IGNORECASE)
43
- ftp.login(args[0][:username].to_s, args[0][:password].to_s)
44
- ftp.chdir("outgoing/")
45
- ftp.nlst.each do |file|
46
- if file.match(file_regexp)
47
- tempfile = Tempfile.new("pacstream")
48
- tempfile.close
49
- ftp.getbinaryfile(file, tempfile.path)
50
- yield File.read(tempfile.path)
51
- end
52
- end
53
- transaction_complete = true
54
- #ftp.quit
55
- end
56
- rescue EOFError
57
- raise "Connection terminated by remote server" unless transaction_complete
58
- rescue Net::FTPPermError
59
- raise "Error while communicating with the pacstream server"
60
- end
61
- end
62
-
63
- end
64
- end
@@ -1,37 +0,0 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__) + "/../")
2
-
3
- require 'rbook/isbn'
4
- require 'rbook/errors'
5
- require 'rbook/titlepage/titlepage_driver'
6
- require 'rbook/titlepage/client'
7
- require 'rbook/titlepage/wwwclient'
8
-
9
- module RBook
10
-
11
- # a convenience module for accessing the SOAP API for http://www.titlepage.com.
12
- # Uses boilerplate code generated by soap4r.
13
- #
14
- # You should be aware of any limits of query volume imposed by the provider - currently a
15
- # maximum of 30 queries per minute is permitted.
16
- #
17
- # All examples require the following two lines at the top of your file:
18
- # require 'rubygems'
19
- # require 'rbook/titlepage'
20
- #
21
- # Basic usage:
22
- # tp = RBook::TitlePage::Client.new
23
- # tp.login('someuser','topsecret')
24
- # puts tp.find("0091835135").inspect
25
- # sleep 3
26
- # puts tp.find("9780672327568").inspect
27
- # tp.logout
28
- #
29
- # Alternative Usage:
30
- # RBook::TitlePage::Client.open("username","password") do |tp|
31
- # puts tp.find("0091835135").inspect
32
- # sleep 3
33
- # puts tp.find("9780672327568").inspect
34
- # end
35
- module TitlePage
36
- end
37
- end