rbook 0.1 → 0.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/README CHANGED
@@ -6,6 +6,7 @@ There are currently 5 key components in the library. Please refer to their
6
6
  respective documentation for information on usage.
7
7
 
8
8
  - RBook::Bisac - Support for reading and writing BISAC files.
9
+ - RBook::GBIP - Very rudimentary support for using the globalbooksinprint.com TCP API.
9
10
  - RBook::ISBN - Convenience methods for validating and converting ISBNs.
10
11
  - RBook::Onix - Support for reading and writing ONIX files.
11
12
  - RBook::TitlePage - A wrapper for the titlepage.com SOAP API.
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'rake/testtask'
5
5
  require "rake/gempackagetask"
6
6
  require "rubygems"
7
7
 
8
- PKG_VERSION = "0.1"
8
+ PKG_VERSION = "0.2"
9
9
  PKG_NAME = "rbook"
10
10
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
11
11
  RUBYFORGE_PROJECT = 'rbook'
@@ -77,7 +77,8 @@ end
77
77
  desc "Report code statistics (KLOCs, etc) from the application"
78
78
  task :stats do
79
79
  require 'vendor/code_statistics'
80
- dirs = [["Library", "lib"],["Functional tests", "test/functional"],["Unit tests", "test/unit"]]
80
+ #dirs = [["Library", "lib"],["Functional tests", "test/functional"],["Unit tests", "test/unit"]]
81
+ dirs = [["Library", "lib"],["Unit tests", "test/unit"]]
81
82
  CodeStatistics.new(*dirs).to_s
82
83
  end
83
84
 
@@ -0,0 +1,12 @@
1
+ # assuming you have rbook installed via rubygems,
2
+ # in a regular script, replace the following require
3
+ # line with these 2 lines:
4
+ # require 'rubygems'
5
+ # require 'rbook/gbip'
6
+ require File.dirname(__FILE__) + '/../lib/rbook/gbip'
7
+
8
+ gbip = RBook::GBIP::POS.new("username", "password")
9
+
10
+ puts gbip.find("0091835135").inspect
11
+ #puts tp.find("1741146712").inspect
12
+
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+
3
+ require 'rbook/onix'
4
+
5
+ reader = RBook::Onix::StreamReader.new(File.dirname(__FILE__)+"/../../test/data/chalice.xml")
6
+ counter = 0
7
+
8
+ reader.each do |product|
9
+ puts product.product_identifier
10
+ counter += 1
11
+ end
12
+
13
+ puts "total of ##{counter.to_s} products"
@@ -5,7 +5,7 @@
5
5
  # require 'rbook/titlepage'
6
6
  require File.dirname(__FILE__) + '/../lib/rbook/titlepage'
7
7
 
8
- RBook::TitlePage.open("username", "password") do |tp|
8
+ RBook::TitlePage::Client.open("username", "password") do |tp|
9
9
 
10
10
  puts tp.find("0091835135").inspect
11
11
  sleep 3
@@ -1,175 +1,29 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + "/../")
2
+
3
+ require 'rbook/bisac/message'
4
+ require 'rbook/bisac/product'
5
+ require 'rbook/isbn'
6
+
1
7
  module RBook
2
8
 
3
- # Ruby class for reading and writing BISAC files.
9
+ # Ruby module for reading and writing BISAC files.
4
10
  # BISAC is a really bad format for electronic exchange of data - ONIX should be
5
11
  # used where possible. Here be dragons.
6
12
  #
7
- # Basic Usage:
8
- # require 'rubygems'
9
- # require 'rbook/bisac'
10
- # bisac = RBook::Bisac.new("Rainbow", "0000000000", "jan06", "1")
11
- # item = {:isbn => "020161622X",
12
- # :title => "Pragmatic Programmer",
13
- # :author => "Hunt Thomas",
14
- # :price => "2995",
15
- # :binding => "PB",
16
- # :pubdate => "061223",
17
- # :publihser => "Pearson Education",
18
- # :imprint => "Addison-Wesley",
19
- # :edition => "1",
20
- # :volume => "1",
21
- # :volumes => "1",
22
- # :status => "O/O"
23
- # }
24
- # bisac.add_item(item)
25
- # bisac.write("/tmp/jan06.txt")
26
- class Bisac
27
-
28
- # creates a new bisac file in memory
29
- # company = company name (10 chars)
30
- # san = company SAN number (12 chars)
31
- # batch = batch name for this file (6 chars)
32
- # code = 1 for new titles, 2 for updated titles (1 char)
33
- def initialize(company, san, batch, code)
34
- @company = company
35
- @san = san
36
- @batch = batch
37
- @code = code
38
- @data = []
39
- end
40
-
41
- # TODO: Not Yet Implemented.
42
- # loads the requested BISAC file into memory. Returns an array of hashes
43
- def self.load(filename)
44
-
45
- end
46
-
47
- # adds a new title to the bisic file. Expects a hash with the required data.
48
- #
49
- # Required hash indexes:
50
- # - :isbn
51
- # - :title
52
- # - :author
53
- # - :price
54
- # - :pubdate
55
- # - :publisher
56
- # - :imprint
57
- # - :edition
58
- # - :binding
59
- # - :volume
60
- # - :volumes
61
- # - :status
62
- def add_item(item)
63
- raise ArgumentError, 'item must be a hash' unless item.kind_of?(Hash)
64
- raise ArgumentError, 'Hash needs an :isbn index' if item[:isbn].nil?
65
- raise ArgumentError, 'Hash needs an :title index' if item[:title].nil?
66
- raise ArgumentError, 'Hash needs an :author index' if item[:author].nil?
67
- raise ArgumentError, 'Hash needs an :price index' if item[:price].nil?
68
- raise ArgumentError, 'Hash needs an :pubdate index' if item[:pubdate].nil?
69
- raise ArgumentError, 'Hash needs an :publisher index' if item[:publisher].nil?
70
- raise ArgumentError, 'Hash needs an :imprint index' if item[:imprint].nil?
71
- raise ArgumentError, 'Hash needs an :volumes index' if item[:volumes].nil?
72
- raise ArgumentError, 'Hash needs an :edition index' if item[:edition].nil?
73
- raise ArgumentError, 'Hash needs an :binding index' if item[:binding].nil?
74
- raise ArgumentError, 'Hash needs an :volume index' if item[:volume].nil?
75
- raise ArgumentError, 'Hash needs an :status index' if item[:status].nil?
76
- @data << item
77
- end
78
-
79
- # converts this bisac file into a string
80
- def to_s
81
- # File Header
82
- content = "**HEADER**"
83
- content << Time.now.strftime("%y%m%d")
84
- content << @company[0,10].ljust(10)
85
- content << @san[0,12].ljust(12)
86
- content << @batch[0,6].ljust(6)
87
- content << @code[0,1].ljust(1)
88
- content << "**PUBSTAT*"
89
- content << "040"
90
- content << "".ljust(201)
91
- content << "\n"
92
-
93
- # File Content
94
- counter = 0
95
- @data.each do |item|
96
- content << item[:isbn][0,10].ljust(10) # 10 digit isbn
97
- content << "1"
98
- content << "N"
99
- content << "N"
100
- content << "B"
101
- content << "N"
102
- content << item[:title][0,30].ljust(30)
103
- content << "N"
104
- content << item[:author][0,30].ljust(30)
105
- content << "N"
106
- content << "A" # author role
107
- content << "N"
108
- content << item[:price][0,7].rjust(7,"0") # current price
109
- content << "N"
110
- content << item[:pubdate][0,6].ljust(6) # published date
111
- content << "N"
112
- content << item[:publisher][0,10].ljust(10) # publisher
113
- content << "N"
114
- content << item[:imprint][0,14].ljust(14) #imprint
115
- content << "N"
116
- content << item[:volumes][0,3].rjust(3,"0") # volumes included in this isbn
117
- content << "N"
118
- content << item[:edition][0,2].rjust(2,"0") # edition
119
- content << "N"
120
- content << item[:binding][0,2].rjust(2) # binding
121
- content << "N"
122
- content << item[:volume][0,3].rjust(3,"0") # volume number
123
- content << "N"
124
- content << "0000000" # new price
125
- content << "N"
126
- content << "000000" # new price effective date
127
- content << "N"
128
- content << " " # audience type
129
- content << "N"
130
- content << item[:status][0,3].rjust(3) # status
131
- content << "N"
132
- content << " " # available date. only use for status' like NYP
133
- content << "N"
134
- content << " " # alternate isbn
135
- content << "N"
136
- content << "999999" # out of print date. only use for status == OP
137
- content << "N"
138
- content << " " # geographic restrictions
139
- content << "N"
140
- content << " " # library of congress catalogue number
141
- content << "N"
142
- content << "".ljust(40) # series title
143
- content << "N"
144
- content << "0" # price code for current price
145
- content << "N"
146
- content << "0" # price code for new price
147
- content << "N"
148
- content << "0000000" # freight pass through price
149
- content << "N"
150
- content << "000000" # new freight pass through price
151
- content << "00000" # last changed date
152
- content << "\n"
153
-
154
-
155
- counter = counter + 1
156
- end
157
-
158
- # File Footer
159
- content << "**TRAILER*"
160
- content << Time.now.strftime("%y%m%d")
161
- content << @batch[0,6].ljust(6)
162
- content << counter.to_s[0,6].ljust(6)
163
- content << "**PUBSTAT*"
164
- content << "".ljust(221)
165
-
166
-
167
- return content
168
- end
13
+ # = Basic Usage
14
+ # require 'rubygems'
15
+ # require 'rbook/bisac'
16
+ # include Rbook
17
+ # msg = Bisac::Message.new('Company', '1234567', '111111', '1'))
18
+ # item = Bisac::Product.new('0123456789')
19
+ # item.title = "A Book"
20
+ # item.author = "Healy, James"
21
+ # item.price = "1995"
22
+ # item.binding = "PB"
23
+ # item.status = "AVL"
24
+ # msg << item
25
+ # puts msg.to_s
26
+ module Bisac
169
27
 
170
- # writes the content of this bisac file out to the specified file
171
- def write(filename)
172
- File.open(filename, "w") { |f| f.puts to_s }
173
- end
174
28
  end
175
29
  end
@@ -0,0 +1,99 @@
1
+
2
+
3
+ module RBook
4
+ module Bisac
5
+
6
+ # Represents a single Bisac File. See RBook::Bisac for a basic
7
+ # usage example.
8
+ class Message
9
+
10
+ attr_accessor :company, :san, :batch, :code, :products
11
+
12
+ # creates a new bisac file in memory
13
+ # params:
14
+ # - company = company name (10 chars)
15
+ # - san = company SAN number (12 chars)
16
+ # - batch = batch name for this file (6 chars)
17
+ # - code = 1 for new titles, 2 for updated titles (1 char)
18
+ def initialize(company, san, batch, code)
19
+ @company = company
20
+ @san = san
21
+ @batch = batch
22
+ @code = code
23
+ @products = []
24
+ end
25
+
26
+ # loads the requested BISAC file into memory.
27
+ # returns a Message object or nil if the file is not
28
+ # a BISAC file
29
+ def self.load(filename)
30
+ msg = self.new(nil,nil,nil,nil)
31
+
32
+ File.open(filename, "r") do |f|
33
+ f.each_line do |l|
34
+ if l[0,10].eql?("**HEADER**")
35
+ msg.company = l[16,10].strip
36
+ msg.san = l[26,12].strip
37
+ msg.batch = l[38,6].strip
38
+ msg.code = l[44,1].strip
39
+ elsif !l[0,11].eql?("**TRAILER**")
40
+ product = RBook::Bisac::Product.from_string(l)
41
+ msg << product unless product.nil?
42
+ end
43
+ end
44
+ end
45
+
46
+ if msg.company.nil? || msg.san.nil? || msg.batch.nil? || msg.code.nil?
47
+ return nil
48
+ else
49
+ return msg
50
+ end
51
+ end
52
+
53
+ # adds a new title to the bisic file. Expects a Rbook::Bisac::Product object.
54
+ def << (item)
55
+ unless item.class == RBook::Bisac::Product
56
+ raise ArgumentError, 'item must be a RBook::Bisac::Product object'
57
+ end
58
+ @products << item
59
+ end
60
+
61
+ # converts this bisac file into a string
62
+ def to_s
63
+ # File Header
64
+ content = "**HEADER**"
65
+ content << Time.now.strftime("%y%m%d")
66
+ content << @company[0,10].ljust(10)
67
+ content << @san[0,12].ljust(12)
68
+ content << @batch[0,6].ljust(6)
69
+ content << @code[0,1].ljust(1)
70
+ content << "**PUBSTAT*"
71
+ content << "040"
72
+ content << "".ljust(201)
73
+ content << "\n"
74
+
75
+ # File Content
76
+ counter = 0
77
+ @products.each do |item|
78
+ content << item.to_s + "\n"
79
+ counter = counter + 1
80
+ end
81
+
82
+ # File Footer
83
+ content << "**TRAILER*"
84
+ content << Time.now.strftime("%y%m%d")
85
+ content << @batch[0,6].ljust(6)
86
+ content << counter.to_s[0,6].ljust(6)
87
+ content << "**PUBSTAT*"
88
+ content << "".ljust(221)
89
+
90
+ return content
91
+ end
92
+
93
+ # writes the content of this bisac file out to the specified file
94
+ def write(filename)
95
+ File.open(filename, "w") { |f| f.puts to_s }
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,176 @@
1
+ module RBook
2
+ module Bisac
3
+
4
+ # Class to represent a single product line in a Bisac File. See
5
+ # RBook::Bisac for basic usage instructions.
6
+ class Product
7
+
8
+ attr_reader :isbn, :title, :author, :price, :pubdate, :publisher
9
+ attr_reader :imprint, :volumes, :edition, :binding, :volume, :status
10
+
11
+ # Creates a new product object with the requested ISBN. Must be a 10 digit ISBN.
12
+ def initialize(isbn)
13
+ raise ArgumentError, 'isbn must 10 chars or less' if isbn.to_s.length > 10
14
+
15
+ @isbn = isbn.to_s
16
+ @title = ""
17
+ @author = ""
18
+ @price = ""
19
+ @pubdate = ""
20
+ @publisher = ""
21
+ @imprint = ""
22
+ @volumes = ""
23
+ @edition = ""
24
+ @binding = ""
25
+ @volume = ""
26
+ @status = ""
27
+ end
28
+
29
+ # sets the products author. Maximum of 30 chars.
30
+ def author=(author)
31
+ @author = author.to_s
32
+ end
33
+
34
+ # sets the products binding. Maximum of 2 chars.
35
+ def binding=(binding)
36
+ @binding = binding.to_s
37
+ end
38
+
39
+ # sets the products edition number. Maximum of 3 chars.
40
+ def edition=(edition)
41
+ @edition = edition.to_s
42
+ end
43
+
44
+ # takes a single line from a BISAC file and attempts to convert
45
+ # it to a Product object
46
+ def self.from_string(s)
47
+ s = s.to_s
48
+ return nil if s.length < 259
49
+ product = self.new(s[0,10])
50
+ product.title = s[15,30].strip
51
+ product.author = s[46,30].strip
52
+ product.price = s[79,7].strip if s[79,7].strip.match(/\A\d{0,7}\Z/)
53
+ product.pubdate = s[87,6].strip if s[87,6].strip.match(/\A\d{6}\Z/)
54
+ product.publisher = s[94,10].strip
55
+ product.imprint = s[105,14].strip
56
+ product.volumes = s[120,3].strip
57
+ product.edition = s[124,2].strip
58
+ product.binding = s[127,2].strip
59
+ product.volume = s[130,3].strip
60
+ product.status = s[153,3].strip
61
+ return product
62
+ end
63
+
64
+ # Sets the products imprint. Maximum of 14 chars.
65
+ def imprint=(imprint)
66
+ @imprint = imprint.to_s
67
+ end
68
+
69
+ # Sets the price imprint. Maximum of 7 chars. Must by a whole
70
+ # number (represent price in cents).
71
+ def price=(price)
72
+ unless price.to_s.match(/\A\d{0,7}\Z/)
73
+ raise ArgumentError, 'price should be a whole number with no more than 7 digits. (price in cents)'
74
+ end
75
+ @price = price.to_s
76
+ end
77
+
78
+ # Sets the products pubdate. Must be in the form YYMMDD
79
+ def pubdate=(pubdate)
80
+ unless pubdate.to_s.match(/\A\d{6}\Z/)
81
+ raise ArgumentError, 'pubdate should be a date in the form YYMMDD.'
82
+ end
83
+ @pubdate = pubdate.to_s
84
+ end
85
+
86
+ # sets the products publisher. Maximum of 10 chars.
87
+ def publisher=(publisher)
88
+ @publisher = publisher.to_s
89
+ end
90
+
91
+ # sets the products status code. Maximum of 3 chars.
92
+ def status=(status)
93
+ @status = status.to_s
94
+ end
95
+
96
+ # sets the products title. Maximum of 30 chars.
97
+ def title=(title)
98
+ @title = title.to_s
99
+ end
100
+
101
+ # Returns the product as a single line ready for inserting into a BISAC file.
102
+ # Doesn't have a \n on the end
103
+ def to_s
104
+ content = ""
105
+ content << @isbn[0,10].ljust(10) # 10 digit isbn
106
+ content << "1"
107
+ content << "N"
108
+ content << "N"
109
+ content << "B"
110
+ content << "N"
111
+ content << @title[0,30].ljust(30)
112
+ content << "N"
113
+ content << @author[0,30].ljust(30)
114
+ content << "N"
115
+ content << "A" # author role
116
+ content << "N"
117
+ content << @price[0,7].rjust(7,"0") # current price
118
+ content << "N"
119
+ content << @pubdate[0,6].ljust(6) # published date
120
+ content << "N"
121
+ content << @publisher[0,10].ljust(10) # publisher
122
+ content << "N"
123
+ content << @imprint[0,14].ljust(14) #imprint
124
+ content << "N"
125
+ content << @volumes[0,3].rjust(3,"0") # volumes included in this isbn
126
+ content << "N"
127
+ content << @edition[0,2].rjust(2,"0") # edition
128
+ content << "N"
129
+ content << @binding[0,2].rjust(2,"0") # binding
130
+ content << "N"
131
+ content << @volume[0,3].rjust(3,"0") # volume number
132
+ content << "N"
133
+ content << "0000000" # new price
134
+ content << "N"
135
+ content << "000000" # new price effective date
136
+ content << "N"
137
+ content << " " # audience type
138
+ content << "N"
139
+ content << @status[0,3].rjust(3) # status
140
+ content << "N"
141
+ content << " " # available date. only use for status' like NYP
142
+ content << "N"
143
+ content << " " # alternate isbn
144
+ content << "N"
145
+ content << "999999" # out of print date. only use for status == OP
146
+ content << "N"
147
+ content << " " # geographic restrictions
148
+ content << "N"
149
+ content << " " # library of congress catalogue number
150
+ content << "N"
151
+ content << "".ljust(40) # series title
152
+ content << "N"
153
+ content << "0" # price code for current price
154
+ content << "N"
155
+ content << "0" # price code for new price
156
+ content << "N"
157
+ content << "0000000" # freight pass through price
158
+ content << "N"
159
+ content << "000000" # new freight pass through price
160
+ content << "00000" # last changed date
161
+
162
+ return content
163
+ end
164
+
165
+ # sets the products volume number. Maximum of 3 chars.
166
+ def volume=(volume)
167
+ @volume = volume.to_s
168
+ end
169
+
170
+ # sets the number of volumes in the set this product belongs to. Maximum of 3 chars.
171
+ def volumes=(volumes)
172
+ @volumes = volumes.to_s
173
+ end
174
+ end
175
+ end
176
+ end