Class: Alexandria::Library
- Inherits:
-
Array
- Object
- Array
- Alexandria::Library
show all
- Extended by:
- GetText
- Includes:
- Exportable, Logging, GetText, Observable
- Defined in:
- lib/alexandria/export_library.rb,
lib/alexandria/import_library.rb,
lib/alexandria/models/library.rb,
lib/alexandria/import_library_csv.rb,
lib/alexandria/ui/init.rb
Defined Under Namespace
Classes: InvalidISBNError, NoISBNError
Constant Summary
collapse
- DIR =
File.join(ENV['HOME'], '.alexandria')
- EXT =
{ book: '.yaml', cover: '.cover' }.freeze
- FIX_BIGNUM_REGEX =
/loaned_since:\s*(\!ruby\/object\:Bignum\s*)?(\d+)\n/
- AMERICAN_UPC_LOOKUP =
{
'014794' => '08041', '018926' => '0445', '02778' => '0449',
'037145' => '0812', '042799' => '0785', '043144' => '0688',
'044903' => '0312', '045863' => '0517', '046594' => '0064',
'047132' => '0152', '051487' => '08167', '051488' => '0140',
'060771' => '0002', '065373' => '0373', '070992' => '0523',
'070993' => '0446', '070999' => '0345', '071001' => '0380',
'071009' => '0440', '071125' => '088677', '071136' => '0451',
'071149' => '0451', '071152' => '0515', '071162' => '0451',
'071268' => '08217', '071831' => '0425', '071842' => '08439',
'072742' => '0441', '076714' => '0671', '076783' => '0553',
'076814' => '0449', '078021' => '0872', '079808' => '0394',
'090129' => '0679', '099455' => '0061', '099769' => '0451'
}.freeze
- @@deleted_libraries =
[]
Instance Attribute Summary collapse
Class Method Summary
collapse
-
.canonicalise_ean(code) ⇒ Object
-
.canonicalise_isbn(isbn) ⇒ Object
-
.deleted_libraries ⇒ Object
-
.ean_checksum(numbers) ⇒ Object
-
.extract_numbers(isbn) ⇒ Object
-
.generate_new_name(existing_libraries, from_base = _('Untitled')) ⇒ Object
-
.identify_csv_type(header) ⇒ Object
LibraryThing has 15 fields (Apr 2010), Goodreads has 29 we shall guess that “PUBLICATION INFO” implies LibraryThing and “Year Published” implies Goodreads.
-
.import_as_csv_file(name, filename, on_iterate_cb, _on_error_cb) ⇒ Object
-
.import_as_isbn_list(name, filename, on_iterate_cb, on_error_cb) ⇒ Object
-
.import_as_tellico_xml_archive(name, filename, on_iterate_cb, _on_error_cb) ⇒ Object
-
.import_autodetect(*args) ⇒ Object
-
.isbn_checksum(numbers) ⇒ Object
-
.jpeg?(file) ⇒ Boolean
-
.load(name) ⇒ Object
-
.loadall ⇒ Object
-
.move(source_library, dest_library, *books) ⇒ Object
-
.neaten(str) ⇒ Object
-
.really_delete_deleted_libraries ⇒ Object
-
.regularize_book_from_yaml(name) ⇒ Object
-
.upc_checksum(numbers) ⇒ Object
-
.upc_convert(upc) ⇒ Object
-
.valid_ean?(ean) ⇒ Boolean
-
.valid_isbn?(isbn) ⇒ Boolean
-
.valid_upc?(upc) ⇒ Boolean
Instance Method Summary
collapse
Methods included from Logging
included, #log
Methods included from Exportable
#export_as_bibtex, #export_as_csv_list, #export_as_html, #export_as_ipod_notes, #export_as_isbn_list, #export_as_onix_xml_archive, #export_as_tellico_xml_archive
Instance Attribute Details
#deleted_books ⇒ Object
Returns the value of attribute deleted_books.
35
36
37
|
# File 'lib/alexandria/models/library.rb', line 35
def deleted_books
@deleted_books
end
|
#name ⇒ Object
Returns the value of attribute name.
34
35
36
|
# File 'lib/alexandria/models/library.rb', line 34
def name
@name
end
|
#ruined_books ⇒ Object
Returns the value of attribute ruined_books.
35
36
37
|
# File 'lib/alexandria/models/library.rb', line 35
def ruined_books
@ruined_books
end
|
#updating ⇒ Object
Returns the value of attribute updating.
35
36
37
|
# File 'lib/alexandria/models/library.rb', line 35
def updating
@updating
end
|
Class Method Details
.canonicalise_ean(code) ⇒ Object
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
|
# File 'lib/alexandria/models/library.rb', line 347
def self.canonicalise_ean(code)
code = code.to_s.delete('- ')
if valid_ean?(code)
return code
elsif valid_isbn?(code)
code = '978' + code[0..8]
return code + String(ean_checksum((code)))
elsif valid_upc?(code)
isbn10 = canonicalise_isbn
code = '978' + isbn10[0..8]
return code + String(ean_checksum((code)))
else
raise InvalidISBNError, code
end
end
|
.canonicalise_isbn(isbn) ⇒ Object
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
|
# File 'lib/alexandria/models/library.rb', line 364
def self.canonicalise_isbn(isbn)
numbers = (isbn)
return isbn if valid_ean?(isbn) && (numbers[0..2] != [9, 7, 8])
canonical = if valid_ean?(isbn)
numbers[3..11] + [isbn_checksum(numbers[3..11])]
elsif valid_upc?(isbn)
prefix = upc_convert(numbers[0..5])
isbn_sans_chcksm = prefix + numbers[(8 + prefix.length)..17]
isbn_sans_chcksm + [isbn_checksum(isbn_sans_chcksm)]
elsif valid_isbn?(isbn)
numbers[0..-2] + [isbn_checksum(numbers[0..-2])]
else
raise InvalidISBNError, isbn
end
canonical.map(&:to_s).join
end
|
.deleted_libraries ⇒ Object
468
469
470
|
# File 'lib/alexandria/models/library.rb', line 468
def self.deleted_libraries
@@deleted_libraries
end
|
.ean_checksum(numbers) ⇒ Object
299
300
301
302
|
# File 'lib/alexandria/models/library.rb', line 299
def self.ean_checksum(numbers)
-(numbers.values_at(1, 3, 5, 7, 9, 11).reduce(:+) * 3 +
numbers.values_at(0, 2, 4, 6, 8, 10).reduce(:+)) % 10
end
|
275
276
277
278
279
280
281
282
|
# File 'lib/alexandria/models/library.rb', line 275
def self.(isbn)
raise NoISBNError, 'Nil ISBN' if isbn.nil? || isbn.empty?
isbn.delete('- ').upcase.split('').map do |x|
raise InvalidISBNError, isbn unless x =~ /[\dX]/
x == 'X' ? 10 : x.to_i
end
end
|
.generate_new_name(existing_libraries, from_base = _('Untitled')) ⇒ Object
54
55
56
57
58
59
60
61
62
63
64
65
|
# File 'lib/alexandria/models/library.rb', line 54
def self.generate_new_name(existing_libraries,
from_base = _('Untitled'))
i = 1
name = nil
all_libraries = existing_libraries + @@deleted_libraries
loop do
name = i == 1 ? from_base : from_base + " #{i}"
break unless all_libraries.find { |x| x.name == name }
i += 1
end
name
end
|
.identify_csv_type(header) ⇒ Object
LibraryThing has 15 fields (Apr 2010), Goodreads has 29 we shall guess that “PUBLICATION INFO” implies LibraryThing and “Year Published” implies Goodreads
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
|
# File 'lib/alexandria/import_library_csv.rb', line 185
def self.identify_csv_type()
is_librarything = false
is_goodreads = false
.each do |head|
if head == "'PUBLICATION INFO'"
is_librarything = true
break
elsif head == 'Year Published'
is_goodreads = true
break
end
end
if is_librarything
return LibraryThingCSVImport.new()
elsif is_goodreads
return GoodreadsCSVImport.new()
end
raise 'Not Recognized' unless is_librarything || is_goodreads
end
|
.import_as_csv_file(name, filename, on_iterate_cb, _on_error_cb) ⇒ Object
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
|
# File 'lib/alexandria/import_library.rb', line 170
def self.import_as_csv_file(name, filename, on_iterate_cb, _on_error_cb)
require 'alexandria/import_library_csv'
books_and_covers = []
line_count = IO.readlines(filename).reduce(0) { |count, _line| count + 1 }
import_count = 0
max_import = line_count - 1
reader = CSV.open(filename, 'r')
= reader.shift
importer = identify_csv_type()
failed_once = false
begin
reader.each do |row|
book = importer.row_to_book(row)
cover = nil
if book.isbn
begin
dl_book, dl_cover = Alexandria::BookProviders.isbn_search(book.isbn)
if dl_book.authors.size > book.authors.size
book.authors = dl_book.authors
end
book.edition = dl_book.edition unless book.edition
cover = dl_cover
rescue
puts "failed to get cover for #{book.title} #{book.isbn}" if $DEBUG
end
end
books_and_covers << [book, cover]
import_count += 1
on_iterate_cb&.call(import_count, max_import)
end
rescue CSV::IllegalFormatError
unless failed_once
failed_once = true
data = File.read(filename)
data.gsub!(/\,\=\"/, ',"')
csv_fixed = Tempfile.new('alexandria_import_csv_fixed_')
csv_fixed.write(data)
csv_fixed.close
reader = CSV.open(csv_fixed.path, 'r')
= reader.shift
importer = identify_csv_type()
retry
end
end
library = Library.load(name)
books_and_covers.each do |book, cover_uri|
puts "Saving #{book.isbn} cover..." if $DEBUG
library.save_cover(book, cover_uri) unless cover_uri.nil?
puts "Saving #{book.isbn}..." if $DEBUG
library << book
library.save(book)
end
[library, []]
end
|
.import_as_isbn_list(name, filename, on_iterate_cb, on_error_cb) ⇒ Object
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
|
# File 'lib/alexandria/import_library.rb', line 241
def self.import_as_isbn_list(name, filename, on_iterate_cb,
on_error_cb)
puts 'Starting import_as_isbn_list... '
isbn_list = IO.readlines(filename).map do |line|
puts "Trying line #{line}" if $DEBUG
begin
[line.chomp, canonicalise_isbn(line.chomp)] unless line == "\n"
rescue => e
puts e.message
[line.chomp, nil]
end
end
puts "Isbn list: #{isbn_list.inspect}"
isbn_list.compact!
return nil if isbn_list.empty?
max_iterations = isbn_list.length * 2
current_iteration = 1
books = []
bad_isbns = []
failed_lookup_isbns = []
isbn_list.each do |isbn|
begin
if isbn[1]
books << Alexandria::BookProviders.isbn_search(isbn[1])
else
bad_isbns << isbn[0]
end
rescue => e
puts e.message
failed_lookup_isbns << isbn[1]
puts "NOTE : ignoring on_error_cb #{on_error_cb}"
end
on_iterate_cb&.call(current_iteration += 1, max_iterations)
end
puts "Bad Isbn list: #{bad_isbns.inspect}" if bad_isbns
library = load(name)
puts "Going with these #{books.length} books: #{books.inspect}" if $DEBUG
books.each do |book, cover_uri|
puts "Saving #{book.isbn} cover..." if $DEBUG
library.save_cover(book, cover_uri) unless cover_uri.nil?
puts "Saving #{book.isbn}..." if $DEBUG
library << book
library.save(book)
on_iterate_cb&.call(current_iteration += 1, max_iterations)
end
[library, bad_isbns, failed_lookup_isbns]
end
|
.import_as_tellico_xml_archive(name, filename, on_iterate_cb, _on_error_cb) ⇒ Object
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
# File 'lib/alexandria/import_library.rb', line 87
def self.import_as_tellico_xml_archive(name, filename,
on_iterate_cb, _on_error_cb)
puts 'Starting import_as_tellico_xml_archive... '
return nil unless system("unzip -qqt \"#{filename}\"")
tmpdir = File.join(Dir.tmpdir, 'tellico_export')
FileUtils.rm_rf(tmpdir) if File.exist?(tmpdir)
Dir.mkdir(tmpdir)
Dir.chdir(tmpdir) do
begin
system("unzip -qq \"#{filename}\"")
file = File.exist?('bookcase.xml') ? 'bookcase.xml' : 'tellico.xml'
xml = REXML::Document.new(File.open(file))
raise unless ['bookcase', 'tellico'].include? xml.root.name
raise unless xml.root.elements.size == 1
collection = xml.root.elements[1]
raise unless collection.name == 'collection'
type = collection.attribute('type').value.to_i
raise unless (type == 2) || (type == 5)
content = []
entries = collection.elements.to_a('entry')
(total = entries.size).times do |n|
entry = entries[n]
elements = entry.elements
keys = ['isbn', 'publisher', 'pub_year', 'binding']
book_elements = [neaten(elements['title'].text)]
book_elements += if !elements['authors'].nil?
[elements['authors'].elements.to_a.map \
{ |x| neaten(x.text) }]
else
[[]]
end
book_elements += keys.map { |key|
neaten(elements[key].text) if elements[key]
}
if book_elements[2].nil? || book_elements[2].strip.empty?
book_elements[2] = nil
else
begin
book_elements[2] = book_elements[2].strip
book_elements[2] = Library.canonicalise_ean(book_elements[2])
rescue => ex
puts book_elements[2]
puts ex.message
puts ex.backtrace.join("\n> ")
raise ex
end
end
book_elements[4] = book_elements[4].to_i unless book_elements[4].nil? puts book_elements.inspect
cover = (neaten(elements['cover'].text) if elements['cover'])
puts cover
book = Book.new(*book_elements)
if elements['rating'] && Book::VALID_RATINGS.member?(elements['rating'].text.to_i)
book.rating = elements['rating'].text.to_i
end
book.notes = neaten(elements['comments'].text) if elements['comments']
content << [book, cover]
on_iterate_cb&.call(n + 1, total)
end
library = Library.load(name)
content.each do |book, cover|
unless cover.nil?
library.save_cover(book,
File.join(Dir.pwd, 'images',
cover))
end
library << book
library.save(book)
end
return [library, []]
rescue => e
puts e.message
return nil
end
end
end
|
.import_autodetect(*args) ⇒ Object
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
# File 'lib/alexandria/import_library.rb', line 65
def self.import_autodetect(*args)
puts args.inspect
filename = args[1]
puts "Filename is #{filename} and ext is #{filename[-4..-1]}"
puts "Beginning import: #{args[0]}, #{args[1]}"
if filename[-4..-1] == '.txt'
import_as_isbn_list(*args)
elsif ['.tc', '.bc'].include? filename[-3..-1]
begin
import_as_tellico_xml_archive(*args)
rescue => e
puts e.message
puts e.backtrace.join("\n>> ")
end
elsif ['.csv'].include? filename[-4..-1]
import_as_csv_file(*args)
else
puts 'Bailing on this import!'
raise 'Not supported type'
end
end
|
.isbn_checksum(numbers) ⇒ Object
284
285
286
287
288
289
290
|
# File 'lib/alexandria/models/library.rb', line 284
def self.isbn_checksum(numbers)
sum = (0...numbers.length).reduce(0) do |accumulator, i|
accumulator + numbers[i] * (i + 1)
end % 11
sum == 10 ? 'X' : sum
end
|
.jpeg?(file) ⇒ Boolean
602
603
604
|
# File 'lib/alexandria/models/library.rb', line 602
def self.jpeg?(file)
IO.read(file, 10)[6..9] == 'JFIF'
end
|
.load(name) ⇒ Object
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
# File 'lib/alexandria/models/library.rb', line 70
def self.load(name)
test = [0, nil]
ruined_books = []
library = Library.new(name)
FileUtils.mkdir_p(library.path) unless File.exist?(library.path)
Dir.chdir(library.path) do
Dir['*' + EXT[:book]].each do |filename|
test[1] = filename if (test[0]).zero?
unless File.size? test[1]
log.warn { "Book file #{test[1]} was empty" }
md = /([\dxX]{10,13})#{EXT[:book]}/.match(filename)
if md
file_isbn = md[1]
ruined_books << [nil, file_isbn, library]
else
log.warn { "Filename #{filename} does not contain an ISBN" }
end
next
end
book = regularize_book_from_yaml(test[1])
old_isbn = book.isbn
old_pub_year = book.publishing_year
begin
begin
book.isbn = canonicalise_ean(book.isbn).to_s unless book.isbn.nil?
raise "Not a book: #{book.inspect}" unless book.is_a?(Book)
rescue InvalidISBNError
book.isbn = old_isbn
end
book.publishing_year = book.publishing_year.to_i unless book.publishing_year.nil?
raise "#{test[1]} isbn is not okay" unless book.isbn == old_isbn
raise "#{test[1]} version is not okay" unless book.version == Alexandria::DATA_VERSION
raise "#{test[1]} pub year is not okay" unless book.publishing_year == old_pub_year
book.library = library.name
if book.isbn.nil? || book.isbn.empty?
if File.exist? library.old_cover(book)
log.debug { "#{library.name}; book #{book.title} has no ISBN, fixing cover image" }
FileUtils::Verbose.mv(library.old_cover(book), library.cover(book))
end
end
library << book
rescue
book.version = Alexandria::DATA_VERSION
savedfilename = library.simple_save(book)
test[0] = test[0] + 1
test[1] = savedfilename
redo unless test[0] > 2
else
test = [0, nil]
end
end
Dir['*' + '_medium.jpg'].each do |medium_cover|
begin
FileUtils.mv(medium_cover,
medium_cover.sub(/_medium\.jpg$/,
EXT[:cover]))
rescue
end
end
Dir['*' + EXT[:cover]].each do |cover|
next if cover[0] == 'g'
md = /(.+)\.cover/.match(cover)
begin
ean = canonicalise_ean(md[1])
rescue
ean = md[1]
end
begin
FileUtils.mv(cover, ean + EXT[:cover]) unless cover == ean + EXT[:cover]
rescue
end
end
FileUtils.rm_f(Dir['*_small.jpg'])
end
library.ruined_books = ruined_books
library
end
|
.loadall ⇒ Object
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
|
# File 'lib/alexandria/models/library.rb', line 224
def self.loadall
a = []
begin
Dir.entries(DIR).each do |file|
next if file =~ /^\./
next unless File.stat(File.join(DIR, file)).directory?
a << load(file)
end
rescue Errno::ENOENT
FileUtils.mkdir_p(DIR)
end
a << load(_('My Library')) if a.empty?
a
end
|
.move(source_library, dest_library, *books) ⇒ Object
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
|
# File 'lib/alexandria/models/library.rb', line 245
def self.move(source_library, dest_library, *books)
dest = dest_library.path
books.each do |book|
FileUtils.mv(source_library.yaml(book), dest)
FileUtils.mv(source_library.cover(book), dest) if File.exist?(source_library.cover(book))
source_library.changed
source_library.old_delete(book)
source_library.notify_observers(source_library,
BOOK_REMOVED,
book)
dest_library.changed
dest_library.delete_if { |book2| book2.ident == book.ident }
dest_library << book
dest_library.notify_observers(dest_library, BOOK_ADDED, book)
end
end
|
.neaten(str) ⇒ Object
293
294
295
296
297
298
299
|
# File 'lib/alexandria/import_library.rb', line 293
def self.neaten(str)
if str
str.strip
else
str
end
end
|
.really_delete_deleted_libraries ⇒ Object
472
473
474
475
476
|
# File 'lib/alexandria/models/library.rb', line 472
def self.really_delete_deleted_libraries
@@deleted_libraries.each do |library|
FileUtils.rm_rf(library.path)
end
end
|
.regularize_book_from_yaml(name) ⇒ Object
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
|
# File 'lib/alexandria/models/library.rb', line 174
def self.regularize_book_from_yaml(name)
text = IO.read(name)
if text =~ /!str:Amazon::Search::Response/
log.debug { "Removing Ruby/Amazon strings from #{name}" }
text.gsub!('!str:Amazon::Search::Response', '')
end
if (md = FIX_BIGNUM_REGEX.match(text))
new_yaml = Time.at(md[2].to_i).to_yaml
new_yaml.sub!(/^\s*\-+\s*/, '')
text.sub!(md[0], "loaned_since: #{new_yaml}\n")
end
book = YAML.safe_load(text, whitelist_classes = [Book, Time])
unless book.isbn.class == String
md = /isbn: (.+)/.match(text)
if md
string_isbn = md[1].strip
book.isbn = string_isbn
end
end
unless book.saved_ident.class == String
md2 = /saved_ident: (.+)/.match(text)
if md2
string_saved_ident = md2[1].strip
log.debug { "fixing saved_ident #{book.saved_ident} -> #{string_saved_ident}" }
book.saved_ident = string_saved_ident
end
end
if (book.isbn.class == String) && book.isbn.empty?
book.isbn = nil end
book
end
|
.upc_checksum(numbers) ⇒ Object
314
315
316
317
|
# File 'lib/alexandria/models/library.rb', line 314
def self.upc_checksum(numbers)
-(numbers.values_at(0, 2, 4, 6, 8, 10).reduce(:+) * 3 +
numbers.values_at(1, 3, 5, 7, 9).reduce(:+)) % 10
end
|
.upc_convert(upc) ⇒ Object
342
343
344
345
|
# File 'lib/alexandria/models/library.rb', line 342
def self.upc_convert(upc)
test_upc = upc.map(&:to_s).join
(AMERICAN_UPC_LOOKUP[test_upc])
end
|
.valid_ean?(ean) ⇒ Boolean
304
305
306
307
308
309
310
311
312
|
# File 'lib/alexandria/models/library.rb', line 304
def self.valid_ean?(ean)
numbers = (ean)
((numbers.length == 13) &&
(ean_checksum(numbers[0..11]) == numbers[12])) ||
((numbers.length == 18) &&
(ean_checksum(numbers[0..11]) == numbers[12]))
rescue InvalidISBNError
false
end
|
.valid_isbn?(isbn) ⇒ Boolean
292
293
294
295
296
297
|
# File 'lib/alexandria/models/library.rb', line 292
def self.valid_isbn?(isbn)
numbers = (isbn)
(numbers.length == 10) && isbn_checksum(numbers).zero?
rescue InvalidISBNError
false
end
|
.valid_upc?(upc) ⇒ Boolean
319
320
321
322
323
324
325
|
# File 'lib/alexandria/models/library.rb', line 319
def self.valid_upc?(upc)
numbers = (upc)
((numbers.length == 17) &&
(upc_checksum(numbers[0..10]) == numbers[11]))
rescue InvalidISBNError
false
end
|
Instance Method Details
#==(object) ⇒ Object
588
589
590
|
# File 'lib/alexandria/models/library.rb', line 588
def ==(object)
object.is_a?(self.class) && object.name == name
end
|
#action_name ⇒ Object
62
63
64
|
# File 'lib/alexandria/ui/init.rb', line 62
def action_name
'MoveIn' + name.gsub(/\s/, '')
end
|
#copy_covers(somewhere) ⇒ Object
592
593
594
595
596
597
598
599
600
|
# File 'lib/alexandria/models/library.rb', line 592
def copy_covers(somewhere)
FileUtils.rm_rf(somewhere) if File.exist?(somewhere)
FileUtils.mkdir(somewhere)
each do |book|
next unless File.exist?(cover(book))
FileUtils.cp(cover(book),
File.join(somewhere, final_cover(book)))
end
end
|
#cover(something) ⇒ Object
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
|
# File 'lib/alexandria/models/library.rb', line 543
def cover(something)
ident = case something
when Book
if something.isbn && !something.isbn.empty?
something.ident
else
"g#{something.ident}" end
when String
something
when Integer
something
else
raise "#{something} is a #{something.class}"
end
File.join(path, ident.to_s + EXT[:cover])
end
|
#delete(book = nil) ⇒ Object
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
|
# File 'lib/alexandria/models/library.rb', line 487
def delete(book = nil)
if book.nil?
raise if @@deleted_libraries.include?(self)
@@deleted_libraries << self
else
if @deleted_books.include?(book)
doubles = @deleted_books.select { |b| b.equal?(book) }
raise ArgumentError, "Book #{book.isbn} was already deleted" unless doubles.empty?
end
@deleted_books << book
i = index(book)
if i && self[i].equal?(book)
changed
old_delete(book) notify_observers(self, BOOK_REMOVED, book)
end
end
end
|
#deleted? ⇒ Boolean
510
511
512
|
# File 'lib/alexandria/models/library.rb', line 510
def deleted?
@@deleted_libraries.include?(self)
end
|
#final_cover(book) ⇒ Object
606
607
608
609
|
# File 'lib/alexandria/models/library.rb', line 606
def final_cover(book)
book.ident + (Library.jpeg?(cover(book)) ? '.jpg' : '.gif')
end
|
#n_rated ⇒ Object
580
581
582
|
# File 'lib/alexandria/models/library.rb', line 580
def n_rated
count { |x| !x.rating.nil? && x.rating > 0 }
end
|
#n_unrated ⇒ Object
584
585
586
|
# File 'lib/alexandria/models/library.rb', line 584
def n_unrated
length - n_rated
end
|
#old_cover(book) ⇒ Object
539
540
541
|
# File 'lib/alexandria/models/library.rb', line 539
def old_cover(book)
File.join(path, book.ident.to_s + EXT[:cover])
end
|
#old_delete ⇒ Object
486
|
# File 'lib/alexandria/models/library.rb', line 486
alias old_delete delete
|
#old_select ⇒ Object
530
|
# File 'lib/alexandria/models/library.rb', line 530
alias old_select select
|
#path ⇒ Object
46
47
48
|
# File 'lib/alexandria/models/library.rb', line 46
def path
File.join(DIR, @name)
end
|
#really_delete_deleted_books ⇒ Object
478
479
480
481
482
483
484
|
# File 'lib/alexandria/models/library.rb', line 478
def really_delete_deleted_books
@deleted_books.each do |book|
[yaml(book), cover(book)].each do |file|
FileUtils.rm_f(file)
end
end
end
|
#save(book, final = false) ⇒ Object
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
|
# File 'lib/alexandria/models/library.rb', line 409
def save(book, final = false)
changed unless final
book.saved_ident ||= book.ident
if book.ident != book.saved_ident
FileUtils.rm(yaml(book.saved_ident))
FileUtils.mv(cover(book.saved_ident), cover(book.ident)) if File.exist?(cover(book.saved_ident))
notify_observers(self, BOOK_UPDATED, book) unless final
book.saved_ident = book.ident
end
already_there = (File.size?(yaml(book)) &&
!@deleted_books.include?(book))
temp_book = book.dup
temp_book.library = nil
File.open(yaml(temp_book), 'w') { |io| io.puts temp_book.to_yaml }
if changed?
notify_observers(self,
already_there ? BOOK_UPDATED : BOOK_ADDED,
book)
end
end
|
#save_cover(book, cover_uri) ⇒ Object
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
|
# File 'lib/alexandria/models/library.rb', line 446
def save_cover(book, cover_uri)
Dir.chdir(path) do
cover_file = cover(book)
File.open(cover_file, 'w') do |io|
uri = URI.parse(cover_uri)
if uri.scheme.nil?
File.open(cover_uri) { |io2| io.puts io2.read }
else
io.puts transport.get(uri)
end
end
File.delete(cover_file) if Alexandria::UI::Icons.blank?(cover_file)
end
end
|
#select ⇒ Object
531
532
533
534
535
536
537
|
# File 'lib/alexandria/models/library.rb', line 531
def select
filtered_library = Library.new(@name)
each do |book|
filtered_library << book if yield(book)
end
filtered_library
end
|
#simple_save(book) ⇒ Object
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
|
# File 'lib/alexandria/models/library.rb', line 387
def simple_save(book)
book.saved_ident = book.ident if book.saved_ident.nil? || book.saved_ident.empty?
if book.ident != book.saved_ident
FileUtils.rm(yaml(book.saved_ident))
end
if File.exist?(cover(book.saved_ident))
begin
FileUtils.mv(cover(book.saved_ident), cover(book.ident))
rescue
end
end
book.saved_ident = book.ident
filename = book.saved_ident.to_s + '.yaml'
File.open(filename, 'w') { |io| io.puts book.to_yaml }
filename
end
|
#transport ⇒ Object
441
442
443
444
|
# File 'lib/alexandria/models/library.rb', line 441
def transport
config = Alexandria::Preferences.instance.http_proxy_config
config ? Net::HTTP.Proxy(*config) : Net::HTTP
end
|
#undelete(book = nil) ⇒ Object
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
|
# File 'lib/alexandria/models/library.rb', line 514
def undelete(book = nil)
if book.nil?
raise unless @@deleted_libraries.include?(self)
@@deleted_libraries.delete(self)
else
raise unless @deleted_books.include?(book)
@deleted_books.delete(book)
unless include?(book)
changed
self << book
notify_observers(self, BOOK_ADDED, book)
end
end
end
|
#updating? ⇒ Boolean
50
51
52
|
# File 'lib/alexandria/models/library.rb', line 50
def updating?
@updating
end
|
#yaml(something, basedir = path) ⇒ Object
561
562
563
564
565
566
567
568
569
570
571
572
573
|
# File 'lib/alexandria/models/library.rb', line 561
def yaml(something, basedir = path)
ident = case something
when Book
something.ident
when String
something
when Integer
something
else
raise "#{something} is #{something.class}"
end
File.join(basedir, ident.to_s + EXT[:book])
end
|