rbook 0.1 → 0.2

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