rbook 0.4.3 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
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