alexandria-book-collection-manager 0.7.9 → 0.7.11
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.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +5 -1
- data/.github/workflows/ruby.yml +36 -22
- data/.rubocop.yml +12 -3
- data/.rubocop_todo.yml +35 -47
- data/.simplecov +2 -2
- data/CHANGELOG.md +71 -24
- data/Gemfile +0 -6
- data/Rakefile +5 -5
- data/alexandria-book-collection-manager.gemspec +24 -21
- data/bin/rake +28 -0
- data/bin/rspec +28 -0
- data/doc/dependency_decisions.yml +32 -26
- data/{bin → exe}/alexandria +1 -3
- data/lib/alexandria/about.rb +1 -0
- data/lib/alexandria/book_providers/bl_provider.rb +4 -6
- data/lib/alexandria/book_providers/{douban.rb → douban_provider.rb} +1 -1
- data/lib/alexandria/book_providers/loc_provider.rb +2 -6
- data/lib/alexandria/book_providers/sbn_provider.rb +2 -12
- data/lib/alexandria/book_providers/thalia_provider.rb +5 -6
- data/lib/alexandria/book_providers/{web.rb → website_based_provider.rb} +20 -1
- data/lib/alexandria/book_providers/{worldcat.rb → world_cat_provider.rb} +3 -4
- data/lib/alexandria/book_providers/z3950_provider.rb +25 -27
- data/lib/alexandria/book_providers.rb +14 -10
- data/lib/alexandria/config.rb +2 -2
- data/lib/alexandria/console.rb +12 -10
- data/lib/alexandria/export_format.rb +3 -2
- data/lib/alexandria/export_library.rb +35 -40
- data/lib/alexandria/import_library.rb +3 -4
- data/lib/alexandria/import_library_csv.rb +2 -2
- data/lib/alexandria/library_collection.rb +1 -1
- data/lib/alexandria/library_store.rb +20 -15
- data/lib/alexandria/logging.rb +22 -21
- data/lib/alexandria/models/book.rb +1 -2
- data/lib/alexandria/models/library.rb +7 -8
- data/lib/alexandria/preferences.rb +7 -19
- data/lib/alexandria/{book_providers/pseudomarc.rb → pseudo_marc_parser.rb} +2 -2
- data/lib/alexandria/scanners/cue_cat.rb +5 -9
- data/lib/alexandria/scanners/{keyboard.rb → keyboard_wedge.rb} +3 -3
- data/lib/alexandria/scanners.rb +2 -2
- data/lib/alexandria/smart_library.rb +9 -5
- data/lib/alexandria/ui/acquire_dialog.rb +42 -45
- data/lib/alexandria/ui/alert_dialog.rb +3 -3
- data/lib/alexandria/ui/barcode_animation.rb +3 -3
- data/lib/alexandria/ui/book_properties_dialog.rb +9 -9
- data/lib/alexandria/ui/book_properties_dialog_base.rb +13 -14
- data/lib/alexandria/ui/builder_base.rb +1 -1
- data/lib/alexandria/ui/callbacks.rb +8 -7
- data/lib/alexandria/ui/confirm_erase_dialog.rb +1 -0
- data/lib/alexandria/ui/conflict_while_copying_dialog.rb +1 -0
- data/lib/alexandria/ui/export_dialog.rb +1 -0
- data/lib/alexandria/ui/{iconview.rb → icon_view_manager.rb} +1 -0
- data/lib/alexandria/ui/icons.rb +2 -2
- data/lib/alexandria/ui/iconview_tooltips.rb +1 -1
- data/lib/alexandria/ui/init.rb +10 -4
- data/lib/alexandria/ui/keep_bad_isbn_dialog.rb +1 -0
- data/lib/alexandria/ui/libraries_combo.rb +1 -0
- data/lib/alexandria/ui/listview.rb +2 -0
- data/lib/alexandria/ui/main_app.rb +3 -1
- data/lib/alexandria/ui/multi_drag_treeview.rb +0 -2
- data/lib/alexandria/ui/new_book_dialog.rb +15 -20
- data/lib/alexandria/ui/new_book_dialog_manual.rb +7 -7
- data/lib/alexandria/ui/new_provider_dialog.rb +1 -0
- data/lib/alexandria/ui/new_smart_library_dialog.rb +2 -1
- data/lib/alexandria/ui/preferences_dialog.rb +4 -4
- data/lib/alexandria/ui/provider_preferences_dialog.rb +1 -0
- data/lib/alexandria/ui/really_delete_dialog.rb +1 -0
- data/lib/alexandria/ui/sidepane_manager.rb +49 -48
- data/lib/alexandria/ui/skip_entry_dialog.rb +1 -0
- data/lib/alexandria/ui/smart_library_properties_dialog.rb +1 -0
- data/lib/alexandria/ui/smart_library_properties_dialog_base.rb +2 -1
- data/lib/alexandria/ui/{sound.rb → sound_effects_player.rb} +3 -0
- data/lib/alexandria/ui/ui_manager.rb +194 -143
- data/lib/alexandria/ui.rb +1 -0
- data/lib/alexandria/version.rb +1 -1
- data/lib/alexandria/web_themes.rb +1 -1
- data/lib/alexandria.rb +6 -5
- data/po/Makefile +1 -1
- data/po/it.po +64 -82
- data/spec/alexandria/book_providers/bl_provider_spec.rb +11 -2
- data/spec/alexandria/book_providers/douban_provider_spec.rb +17 -0
- data/spec/alexandria/book_providers/loc_provider_spec.rb +10 -2
- data/spec/alexandria/book_providers/sbn_provider_spec.rb +10 -2
- data/spec/alexandria/book_providers/thalia_provider_spec.rb +9 -1
- data/spec/alexandria/book_providers/world_cat_provider_spec.rb +30 -10
- data/spec/alexandria/book_providers/z3950_provider_spec.rb +22 -0
- data/spec/alexandria/book_spec.rb +5 -3
- data/spec/alexandria/console_spec.rb +1 -1
- data/spec/alexandria/export_library_spec.rb +65 -19
- data/spec/alexandria/library_collection_spec.rb +24 -0
- data/spec/alexandria/library_spec.rb +68 -53
- data/spec/alexandria/library_store_spec.rb +33 -1
- data/spec/alexandria/preferences_spec.rb +7 -7
- data/spec/alexandria/pseudo_marc_parser_spec.rb +71 -0
- data/spec/alexandria/scanners/cue_cat_spec.rb +11 -4
- data/spec/alexandria/scanners/keyboard_wedge_spec.rb +47 -0
- data/spec/alexandria/smart_library_spec.rb +7 -5
- data/spec/alexandria/ui/about_dialog_spec.rb +2 -2
- data/spec/alexandria/ui/acquire_dialog_spec.rb +8 -3
- data/spec/alexandria/ui/alert_dialog_spec.rb +6 -4
- data/spec/alexandria/ui/bad_isbns_dialog_spec.rb +2 -2
- data/spec/alexandria/ui/book_properties_dialog_spec.rb +5 -5
- data/spec/alexandria/ui/confirm_erase_dialog_spec.rb +19 -3
- data/spec/alexandria/ui/conflict_while_copying_dialog_spec.rb +2 -2
- data/spec/alexandria/ui/error_dialog_spec.rb +14 -3
- data/spec/alexandria/ui/export_dialog_spec.rb +6 -6
- data/spec/alexandria/ui/{iconview_spec.rb → icon_view_manager_spec.rb} +2 -2
- data/spec/alexandria/ui/import_dialog_spec.rb +3 -3
- data/spec/alexandria/ui/keep_bad_isbn_dialog_spec.rb +2 -2
- data/spec/alexandria/ui/main_app_spec.rb +0 -2
- data/spec/alexandria/ui/new_book_dialog_manual_spec.rb +5 -5
- data/spec/alexandria/ui/new_book_dialog_spec.rb +7 -4
- data/spec/alexandria/ui/new_provider_dialog_spec.rb +3 -3
- data/spec/alexandria/ui/new_smart_library_dialog_spec.rb +9 -7
- data/spec/alexandria/ui/preferences_dialog_spec.rb +2 -2
- data/spec/alexandria/ui/provider_preferences_dialog_spec.rb +22 -7
- data/spec/alexandria/ui/really_delete_dialog_spec.rb +2 -2
- data/spec/alexandria/ui/sidepane_manager_spec.rb +2 -2
- data/spec/alexandria/ui/skip_entry_dialog_spec.rb +19 -3
- data/spec/alexandria/ui/smart_library_properties_dialog_spec.rb +2 -2
- data/spec/alexandria/ui/ui_manager_spec.rb +7 -5
- data/spec/end_to_end/basic_run_spec.rb +2 -1
- data/spec/spec_helper.rb +26 -33
- data/tasks/setup.rb +1 -1
- data/util/rake/fileinstall.rb +12 -13
- data/util/rake/gettextgenerate.rb +1 -1
- data/util/rake/omfgenerate.rb +1 -1
- metadata +97 -64
- /data/spec/alexandria/ui/{sound_spec.rb → sound_effects_player_spec.rb} +0 -0
|
@@ -11,12 +11,11 @@ RSpec.describe Alexandria::ExportLibrary do
|
|
|
11
11
|
loader = Alexandria::LibraryStore.new(TESTDIR)
|
|
12
12
|
loader.load_library("My Library")
|
|
13
13
|
end
|
|
14
|
-
let(:format) { Alexandria::ExportFormat.all.find {
|
|
14
|
+
let(:format) { Alexandria::ExportFormat.all.find { _1.message == message } }
|
|
15
15
|
let(:outfile) do
|
|
16
16
|
outfile_base = format.ext ? "my-library.#{format.ext}" : "my-library"
|
|
17
|
-
File.join(Dir.
|
|
17
|
+
File.join(Dir.mktmpdir, outfile_base)
|
|
18
18
|
end
|
|
19
|
-
let(:unsorted) { Alexandria::LibrarySortOrder::Unsorted.new }
|
|
20
19
|
|
|
21
20
|
before do
|
|
22
21
|
test_library = File.join(LIBDIR, "0.6.2")
|
|
@@ -24,7 +23,7 @@ RSpec.describe Alexandria::ExportLibrary do
|
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
after do
|
|
27
|
-
FileUtils.rm_rf(outfile)
|
|
26
|
+
FileUtils.rm_rf(outfile)
|
|
28
27
|
end
|
|
29
28
|
|
|
30
29
|
describe "#export_as_csv_list" do
|
|
@@ -38,7 +37,7 @@ RSpec.describe Alexandria::ExportLibrary do
|
|
|
38
37
|
sort_by_title = Alexandria::LibrarySortOrder.new(:title)
|
|
39
38
|
format.invoke(my_library, sort_by_title, outfile)
|
|
40
39
|
rows = load_rows_from_csv
|
|
41
|
-
titles = rows.map {
|
|
40
|
+
titles = rows.map { _1["Title"] }
|
|
42
41
|
expect(titles).to eq titles.sort
|
|
43
42
|
end
|
|
44
43
|
|
|
@@ -46,7 +45,7 @@ RSpec.describe Alexandria::ExportLibrary do
|
|
|
46
45
|
sort_by_date_desc = Alexandria::LibrarySortOrder.new(:publishing_year, false)
|
|
47
46
|
format.invoke(my_library, sort_by_date_desc, outfile)
|
|
48
47
|
rows = load_rows_from_csv
|
|
49
|
-
dates = rows.map {
|
|
48
|
+
dates = rows.map { _1["Year Published"] }
|
|
50
49
|
expect(dates).to eq dates.sort.reverse
|
|
51
50
|
end
|
|
52
51
|
end
|
|
@@ -55,12 +54,13 @@ RSpec.describe Alexandria::ExportLibrary do
|
|
|
55
54
|
let(:message) { :export_as_html }
|
|
56
55
|
|
|
57
56
|
it "can export unsorted" do
|
|
58
|
-
format.invoke(my_library,
|
|
57
|
+
format.invoke(my_library, Alexandria::LibrarySortOrder::Unsorted.new,
|
|
58
|
+
outfile, Alexandria::WebTheme.all.first)
|
|
59
59
|
index = File.join(outfile, "index.html")
|
|
60
60
|
|
|
61
61
|
aggregate_failures do
|
|
62
|
-
expect(
|
|
63
|
-
expect(
|
|
62
|
+
expect(outfile).to be_an_existing_file
|
|
63
|
+
expect(index).to be_an_existing_file
|
|
64
64
|
expect(File.size(index)).to be_nonzero
|
|
65
65
|
end
|
|
66
66
|
end
|
|
@@ -70,9 +70,9 @@ RSpec.describe Alexandria::ExportLibrary do
|
|
|
70
70
|
let(:message) { :export_as_onix_xml_archive }
|
|
71
71
|
|
|
72
72
|
it "can export unsorted" do
|
|
73
|
-
format.invoke(my_library,
|
|
73
|
+
format.invoke(my_library, Alexandria::LibrarySortOrder::Unsorted.new, outfile)
|
|
74
74
|
aggregate_failures do
|
|
75
|
-
expect(
|
|
75
|
+
expect(outfile).to be_an_existing_file
|
|
76
76
|
expect(File.size(outfile)).to be_nonzero
|
|
77
77
|
end
|
|
78
78
|
end
|
|
@@ -82,9 +82,9 @@ RSpec.describe Alexandria::ExportLibrary do
|
|
|
82
82
|
let(:message) { :export_as_tellico_xml_archive }
|
|
83
83
|
|
|
84
84
|
it "can export unsorted" do
|
|
85
|
-
format.invoke(my_library,
|
|
85
|
+
format.invoke(my_library, Alexandria::LibrarySortOrder::Unsorted.new, outfile)
|
|
86
86
|
aggregate_failures do
|
|
87
|
-
expect(
|
|
87
|
+
expect(outfile).to be_an_existing_file
|
|
88
88
|
expect(File.size(outfile)).to be_nonzero
|
|
89
89
|
end
|
|
90
90
|
end
|
|
@@ -92,12 +92,58 @@ RSpec.describe Alexandria::ExportLibrary do
|
|
|
92
92
|
|
|
93
93
|
describe "#export_as_bibtex" do
|
|
94
94
|
let(:message) { :export_as_bibtex }
|
|
95
|
+
let(:expected_content) do
|
|
96
|
+
<<~BIBTEX
|
|
97
|
+
%Generated on #{Date.today} by: Alexandria #{Alexandria::DISPLAY_VERSION}
|
|
98
|
+
%
|
|
99
|
+
|
|
100
|
+
@BOOK{William1,
|
|
101
|
+
author = "William Gibson",
|
|
102
|
+
title = "Pattern Recognition",
|
|
103
|
+
publisher = "Penguin Books Ltd",
|
|
104
|
+
year = 2004
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@BOOK{Francoise1,
|
|
108
|
+
author = "Francoise Sagan and Irene Ash",
|
|
109
|
+
title = "Bonjour Tristesse",
|
|
110
|
+
publisher = "Penguin Books Ltd",
|
|
111
|
+
OPTnote = "Essential penguin",
|
|
112
|
+
year = 1998
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@BOOK{Kazuo1,
|
|
116
|
+
author = "Kazuo Ishiguro",
|
|
117
|
+
title = "An Artist of the Floating World",
|
|
118
|
+
publisher = "Faber and Faber",
|
|
119
|
+
year = 1999
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@BOOK{Ursula1,
|
|
123
|
+
author = "Ursula Le Guin",
|
|
124
|
+
title = "The Dispossessed",
|
|
125
|
+
publisher = "Gollancz",
|
|
126
|
+
OPTnote = "Gollancz S.F.",
|
|
127
|
+
year = 2006
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@BOOK{Neil1,
|
|
131
|
+
author = "Neil Gaiman",
|
|
132
|
+
title = "Neverwhere",
|
|
133
|
+
publisher = "Headline Review",
|
|
134
|
+
OPTnote = "The Author's Preferred Text",
|
|
135
|
+
year = 2005
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
BIBTEX
|
|
139
|
+
end
|
|
95
140
|
|
|
96
141
|
it "can export unsorted" do
|
|
97
|
-
format.invoke(my_library,
|
|
142
|
+
format.invoke(my_library, Alexandria::LibrarySortOrder::Unsorted.new, outfile)
|
|
98
143
|
aggregate_failures do
|
|
99
|
-
expect(
|
|
144
|
+
expect(outfile).to be_an_existing_file
|
|
100
145
|
expect(File.size(outfile)).to be_nonzero
|
|
146
|
+
expect(File.read(outfile)).to eq expected_content
|
|
101
147
|
end
|
|
102
148
|
end
|
|
103
149
|
end
|
|
@@ -106,9 +152,9 @@ RSpec.describe Alexandria::ExportLibrary do
|
|
|
106
152
|
let(:message) { :export_as_isbn_list }
|
|
107
153
|
|
|
108
154
|
it "can export unsorted" do
|
|
109
|
-
format.invoke(my_library,
|
|
155
|
+
format.invoke(my_library, Alexandria::LibrarySortOrder::Unsorted.new, outfile)
|
|
110
156
|
aggregate_failures do
|
|
111
|
-
expect(
|
|
157
|
+
expect(outfile).to be_an_existing_file
|
|
112
158
|
expect(File.size(outfile)).to be_nonzero
|
|
113
159
|
end
|
|
114
160
|
end
|
|
@@ -118,11 +164,11 @@ RSpec.describe Alexandria::ExportLibrary do
|
|
|
118
164
|
let(:message) { :export_as_ipod_notes }
|
|
119
165
|
|
|
120
166
|
it "can export unsorted" do
|
|
121
|
-
format.invoke(my_library,
|
|
167
|
+
format.invoke(my_library, Alexandria::LibrarySortOrder::Unsorted.new, outfile, nil)
|
|
122
168
|
index = File.join(outfile, "index.linx")
|
|
123
169
|
|
|
124
170
|
aggregate_failures do
|
|
125
|
-
expect(
|
|
171
|
+
expect(outfile).to be_an_existing_file
|
|
126
172
|
expect(File.size(index)).to be_nonzero
|
|
127
173
|
end
|
|
128
174
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This file is part of Alexandria.
|
|
4
|
+
#
|
|
5
|
+
# See the file README.md for authorship and licensing information.
|
|
6
|
+
|
|
7
|
+
require "spec_helper"
|
|
8
|
+
|
|
9
|
+
RSpec.describe Alexandria::LibraryCollection do
|
|
10
|
+
describe "#ruined_books" do
|
|
11
|
+
before do
|
|
12
|
+
test_library = File.join(LIBDIR, "0.6.2")
|
|
13
|
+
FileUtils.cp_r(test_library, TESTDIR)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "lists ISBNs of empty files with their libraries" do
|
|
17
|
+
FileUtils.touch File.join(TESTDIR, "My Library", "0740704923.yaml")
|
|
18
|
+
collection = described_class.instance
|
|
19
|
+
collection.reload
|
|
20
|
+
library = collection.all_libraries.first
|
|
21
|
+
expect(collection.ruined_books).to eq [[nil, "0740704923", library]]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -12,62 +12,71 @@ describe Alexandria::Library do
|
|
|
12
12
|
describe "::EXT" do
|
|
13
13
|
it "has symbolic references to file extensions" do
|
|
14
14
|
extensions = Alexandria::Library::EXT
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
aggregate_failures do
|
|
16
|
+
expect(extensions[:book]).not_to be_nil
|
|
17
|
+
expect(extensions[:cover]).not_to be_nil
|
|
18
|
+
end
|
|
17
19
|
end
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
describe "#valid_isbn?" do
|
|
21
23
|
it "returns a true value for valid isbns" do
|
|
22
24
|
["014143984X", "0-345-43192-8"].each do |x|
|
|
23
|
-
expect(described_class.valid_isbn?(x)).to
|
|
25
|
+
expect(described_class.valid_isbn?(x)).to be true
|
|
24
26
|
end
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
describe "#valid_ean?" do
|
|
29
31
|
it "returns a true value for valid EANs" do
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
aggregate_failures do
|
|
33
|
+
expect(described_class.valid_ean?("9780345431929")).to be true
|
|
34
|
+
expect(described_class.valid_ean?("978034543192912345")).to be true
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
# Regression test: this EAN has a checksum of 10, which should be
|
|
37
|
+
# treated like a checksum of 0.
|
|
38
|
+
expect(described_class.valid_ean?("9784047041790")).to be true
|
|
39
|
+
end
|
|
36
40
|
end
|
|
37
41
|
|
|
38
42
|
it "returns a false value for invalid EANs" do
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
expect(described_class.valid_ean?("9780345431929123456")).to be_falsey
|
|
43
|
-
expect(described_class.valid_ean?("9780345431928")).to be_falsey
|
|
44
|
-
expect(described_class.valid_ean?("9780345431929A")).to be_falsey
|
|
43
|
+
invalid_eans = ["780345431929", "97803454319290", "97803454319291234",
|
|
44
|
+
"9780345431929123456", "9780345431928", "9780345431929A",
|
|
45
|
+
"9784047041791"]
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
aggregate_failures do
|
|
48
|
+
invalid_eans.each do |ean|
|
|
49
|
+
expect(described_class.valid_ean?(ean)).to be false
|
|
50
|
+
end
|
|
51
|
+
end
|
|
47
52
|
end
|
|
48
53
|
end
|
|
49
54
|
|
|
50
55
|
describe "#valid_upc?" do
|
|
51
56
|
it "returns a true value for valid UPCs" do
|
|
52
|
-
expect(described_class.valid_upc?("97803454319312356")).to
|
|
57
|
+
expect(described_class.valid_upc?("97803454319312356")).to be true
|
|
53
58
|
end
|
|
54
59
|
|
|
55
60
|
it "returns a false value for invalid UPCs" do
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
aggregate_failures do
|
|
62
|
+
expect(described_class.valid_upc?("978034543193123567")).to be false
|
|
63
|
+
expect(described_class.valid_upc?("9780345431931235")).to be false
|
|
58
64
|
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
expect(described_class.valid_upc?("97803454319412356")).to be false
|
|
66
|
+
expect(described_class.valid_upc?("97803454319212356")).to be false
|
|
67
|
+
end
|
|
61
68
|
end
|
|
62
69
|
end
|
|
63
70
|
|
|
64
71
|
describe "#canonicalise_isbn" do
|
|
65
72
|
it "returns the correct value for several examples" do
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
aggregate_failures do
|
|
74
|
+
expect(described_class.canonicalise_isbn("014143984X")).to eq "014143984X"
|
|
75
|
+
expect(described_class.canonicalise_isbn("0-345-43192-8")).to eq "0345431928"
|
|
76
|
+
expect(described_class.canonicalise_isbn("3522105907")).to eq "3522105907"
|
|
77
|
+
# EAN number
|
|
78
|
+
expect(described_class.canonicalise_isbn("9780345431929")).to eq "0345431928"
|
|
79
|
+
end
|
|
71
80
|
end
|
|
72
81
|
end
|
|
73
82
|
|
|
@@ -75,7 +84,7 @@ describe Alexandria::Library do
|
|
|
75
84
|
let(:my_library) { loader.load_library("Empty") }
|
|
76
85
|
|
|
77
86
|
before do
|
|
78
|
-
FileUtils.
|
|
87
|
+
FileUtils.mkdir_p(TESTDIR)
|
|
79
88
|
end
|
|
80
89
|
|
|
81
90
|
it "disallows multiple deletion of the same copy of a book" do
|
|
@@ -136,21 +145,27 @@ describe Alexandria::Library do
|
|
|
136
145
|
end
|
|
137
146
|
|
|
138
147
|
it "can be loaded" do
|
|
139
|
-
|
|
140
|
-
|
|
148
|
+
aggregate_failures do
|
|
149
|
+
expect(libs.size).to eq(1)
|
|
150
|
+
expect(my_library.size).to eq(3)
|
|
151
|
+
end
|
|
141
152
|
end
|
|
142
153
|
|
|
143
|
-
it "imports cleanly from version 0.6.1 data format" do
|
|
144
|
-
# Malory
|
|
154
|
+
it "imports Malory book cleanly from version 0.6.1 data format" do
|
|
145
155
|
malory_book = my_library.find { |b| b.isbn == "9780192812179" }
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
156
|
+
aggregate_failures do
|
|
157
|
+
expect(malory_book.publisher).to eq("Oxford University Press")
|
|
158
|
+
expect(malory_book.authors).to include "Vinaver"
|
|
159
|
+
expect(malory_book.version).to eq(Alexandria::DATA_VERSION)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
149
162
|
|
|
150
|
-
|
|
163
|
+
it "imports Guide to LaTeX cleanly from version 0.6.1 data format" do
|
|
151
164
|
latex_book = my_library.find { |b| b.title.include? "Latex" }
|
|
152
|
-
|
|
153
|
-
|
|
165
|
+
aggregate_failures do
|
|
166
|
+
expect(latex_book.isbn).to eq("9780201398250")
|
|
167
|
+
expect(latex_book.publisher).to eq("Addison Wesley")
|
|
168
|
+
end
|
|
154
169
|
end
|
|
155
170
|
end
|
|
156
171
|
|
|
@@ -168,16 +183,20 @@ describe Alexandria::Library do
|
|
|
168
183
|
end
|
|
169
184
|
|
|
170
185
|
it "can be loaded" do
|
|
171
|
-
|
|
172
|
-
|
|
186
|
+
aggregate_failures do
|
|
187
|
+
expect(libs.size).to eq(1)
|
|
188
|
+
expect(my_library.size).to eq(2)
|
|
189
|
+
end
|
|
173
190
|
end
|
|
174
191
|
|
|
175
192
|
it "loads a book with ISBN" do
|
|
176
193
|
# Guide to LaTeX
|
|
177
194
|
latex_book = my_library.find { |b| b.title.include? "Latex" }
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
195
|
+
aggregate_failures do
|
|
196
|
+
expect(latex_book.isbn).to eq("9780201398250")
|
|
197
|
+
expect(latex_book.publisher).to eq("Addison Wesley")
|
|
198
|
+
expect(latex_book.version).to eq(Alexandria::DATA_VERSION)
|
|
199
|
+
end
|
|
181
200
|
end
|
|
182
201
|
|
|
183
202
|
it "loads a book without ISBN" do
|
|
@@ -189,13 +208,9 @@ describe Alexandria::Library do
|
|
|
189
208
|
it "saves loaded books properly" do
|
|
190
209
|
my_library.each { |book| my_library.save(book, true) }
|
|
191
210
|
my_library_reloaded = loader.load_all_libraries[0]
|
|
192
|
-
expect(my_library_reloaded.size).to eq(2)
|
|
193
|
-
|
|
194
|
-
latex_book = my_library_reloaded.find { |b| b.title.include? "Latex" }
|
|
195
|
-
expect(latex_book.publisher).to eq("Addison Wesley")
|
|
196
211
|
|
|
197
|
-
|
|
198
|
-
|
|
212
|
+
expect(my_library_reloaded.map(&:publisher))
|
|
213
|
+
.to contain_exactly("O'Reilley", "Addison Wesley")
|
|
199
214
|
end
|
|
200
215
|
end
|
|
201
216
|
|
|
@@ -224,10 +239,10 @@ describe Alexandria::Library do
|
|
|
224
239
|
described_class.move(source, target, book)
|
|
225
240
|
|
|
226
241
|
aggregate_failures do
|
|
227
|
-
expect(
|
|
228
|
-
expect(
|
|
229
|
-
expect(
|
|
230
|
-
expect(
|
|
242
|
+
expect(source.yaml(book)).not_to be_an_existing_file
|
|
243
|
+
expect(source.cover(book)).not_to be_an_existing_file
|
|
244
|
+
expect(target.yaml(book)).to be_an_existing_file
|
|
245
|
+
expect(target.cover(book)).to be_an_existing_file
|
|
231
246
|
end
|
|
232
247
|
end
|
|
233
248
|
end
|
|
@@ -236,7 +251,7 @@ describe Alexandria::Library do
|
|
|
236
251
|
let(:my_library) { loader.load_library("Empty") }
|
|
237
252
|
|
|
238
253
|
before do
|
|
239
|
-
FileUtils.
|
|
254
|
+
FileUtils.mkdir_p(TESTDIR)
|
|
240
255
|
end
|
|
241
256
|
|
|
242
257
|
it "changes the library's name" do
|
|
@@ -246,7 +261,7 @@ describe Alexandria::Library do
|
|
|
246
261
|
|
|
247
262
|
it "moves the library's directory" do
|
|
248
263
|
my_library.name = "Really Empty"
|
|
249
|
-
expect(File.
|
|
264
|
+
expect(File.join(TESTDIR, "Really Empty")).to be_an_existing_file
|
|
250
265
|
end
|
|
251
266
|
end
|
|
252
267
|
end
|
|
@@ -16,7 +16,7 @@ RSpec.describe Alexandria::LibraryStore do
|
|
|
16
16
|
aggregate_failures do
|
|
17
17
|
expect(smart_libs.size).to eq 5
|
|
18
18
|
smart_libs.each do |lib|
|
|
19
|
-
expect(
|
|
19
|
+
expect(lib.yaml).to be_an_existing_file
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
end
|
|
@@ -34,4 +34,36 @@ RSpec.describe Alexandria::LibraryStore do
|
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
|
+
|
|
38
|
+
describe "#load_all_libraries" do
|
|
39
|
+
before do
|
|
40
|
+
test_library = File.join(LIBDIR, "0.6.2")
|
|
41
|
+
FileUtils.cp_r(test_library, TESTDIR)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "loads the libraries in the target directory" do
|
|
45
|
+
result = loader.load_all_libraries
|
|
46
|
+
aggregate_failures do
|
|
47
|
+
expect(result.count).to eq 1
|
|
48
|
+
expect(result.first.map(&:title))
|
|
49
|
+
.to contain_exactly("Pattern Recognition", "Bonjour Tristesse",
|
|
50
|
+
"An Artist of the Floating World", "The Dispossessed",
|
|
51
|
+
"Neverwhere")
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "lists ISBNs of empty files in ruined books" do
|
|
56
|
+
FileUtils.touch File.join(TESTDIR, "My Library", "0740704923.yaml")
|
|
57
|
+
result = loader.load_all_libraries
|
|
58
|
+
library = result.first
|
|
59
|
+
expect(library.ruined_books).to eq ["0740704923"]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "skips empty files with names that are not valid ISBNs" do
|
|
63
|
+
FileUtils.touch File.join(TESTDIR, "My Library", "12345.yaml")
|
|
64
|
+
result = loader.load_all_libraries
|
|
65
|
+
library = result.first
|
|
66
|
+
expect(library.ruined_books).to be_empty
|
|
67
|
+
end
|
|
68
|
+
end
|
|
37
69
|
end
|
|
@@ -11,17 +11,17 @@ describe Alexandria::Preferences do
|
|
|
11
11
|
|
|
12
12
|
describe "#get_variable" do
|
|
13
13
|
it "returns nil fetching unknown setting" do
|
|
14
|
-
expect(instance.get_variable("does_not_exist")).to
|
|
14
|
+
expect(instance.get_variable("does_not_exist")).to be_nil
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
it "allows fetching by string" do
|
|
18
18
|
instance.toolbar_visible = false
|
|
19
|
-
expect(instance.get_variable("toolbar_visible")).to
|
|
19
|
+
expect(instance.get_variable("toolbar_visible")).to be false
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
it "allows fetching by symbol" do
|
|
23
23
|
instance.toolbar_visible = true
|
|
24
|
-
expect(instance.get_variable(:toolbar_visible)).to
|
|
24
|
+
expect(instance.get_variable(:toolbar_visible)).to be true
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -29,23 +29,23 @@ describe Alexandria::Preferences do
|
|
|
29
29
|
it "allows setting by string" do
|
|
30
30
|
instance.toolbar_visible = false
|
|
31
31
|
instance.set_variable("toolbar_visible", true)
|
|
32
|
-
expect(instance.toolbar_visible).to
|
|
32
|
+
expect(instance.toolbar_visible).to be true
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
it "allows setting by symbol" do
|
|
36
36
|
instance.toolbar_visible = false
|
|
37
37
|
instance.set_variable(:toolbar_visible, true)
|
|
38
|
-
expect(instance.toolbar_visible).to
|
|
38
|
+
expect(instance.toolbar_visible).to be true
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
it "allows setting known setting to false" do
|
|
43
43
|
instance.toolbar_visible = false
|
|
44
|
-
expect(instance.toolbar_visible).to
|
|
44
|
+
expect(instance.toolbar_visible).to be false
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
it "resets known setting by setting to nil" do
|
|
48
48
|
instance.toolbar_visible = nil
|
|
49
|
-
expect(instance.toolbar_visible).to
|
|
49
|
+
expect(instance.toolbar_visible).to be true
|
|
50
50
|
end
|
|
51
51
|
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (C) 2022 Matijs van Zuijlen
|
|
4
|
+
#
|
|
5
|
+
# Alexandria is free software; you can redistribute it and/or
|
|
6
|
+
# modify it under the terms of the GNU General Public License as
|
|
7
|
+
# published by the Free Software Foundation; either version 2 of the
|
|
8
|
+
# License, or (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# Alexandria is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13
|
+
# General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU General Public
|
|
16
|
+
# License along with Alexandria; see the file COPYING. If not,
|
|
17
|
+
# write to the Free Software Foundation, Inc., 51 Franklin Street,
|
|
18
|
+
# Fifth Floor, Boston, MA 02110-1301 USA.
|
|
19
|
+
|
|
20
|
+
require "spec_helper"
|
|
21
|
+
|
|
22
|
+
RSpec.describe Alexandria::PseudoMarcParser do
|
|
23
|
+
describe ".marc_text_to_book" do
|
|
24
|
+
let(:marc_text) do
|
|
25
|
+
<<~MARC
|
|
26
|
+
00991pam 2200289 a 4500
|
|
27
|
+
001 426456
|
|
28
|
+
005 19820209000000.0
|
|
29
|
+
008 811005s1981 maua b 001 0 eng#{' '}
|
|
30
|
+
035 $9 (DLC) 81017108
|
|
31
|
+
906 $a 7 $b cbc $c orignew $d 1 $e ocip $f 19 $g y-gencatlg
|
|
32
|
+
010 $a 81017108#{' '}
|
|
33
|
+
020 $a 0805335587
|
|
34
|
+
020 $a 0805335579 (pbk.)
|
|
35
|
+
040 $a DLC $c DLC $d DLC
|
|
36
|
+
050 00 $a QA612 $b .G7
|
|
37
|
+
082 00 $a 514/.2 $2 19
|
|
38
|
+
100 1 $a Greenberg, Marvin J.
|
|
39
|
+
245 10 $a Algebraic topology : $b a first course / $c Marvin J. Greenberg, John R. Harper.
|
|
40
|
+
260 $a Reading, Mass. : $b Benjamin/Cummings Pub. Co., $c 1981.
|
|
41
|
+
300 $a xi, 311 p. : $b ill. ; $c 24 cm.
|
|
42
|
+
440 0 $a Mathematics lecture note series ; $v 58
|
|
43
|
+
500 $a "A revision of the first author's Lectures on algebraic topology"--P.
|
|
44
|
+
504 $a Bibliography: p. 303-307.
|
|
45
|
+
500 $a Includes index.
|
|
46
|
+
650 0 $a Algebraic topology.
|
|
47
|
+
700 1 $a Harper, John R., $d 1941-
|
|
48
|
+
991 $b c-GenColl $h QA612 $i .G7 $p 00035736761 $t Copy 1 $w BOOKS
|
|
49
|
+
MARC
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "returns a book with the correct attributes" do
|
|
53
|
+
result = described_class.marc_text_to_book(marc_text,
|
|
54
|
+
described_class::USMARC_MAPPINGS)
|
|
55
|
+
aggregate_failures do
|
|
56
|
+
expect(result.title).to eq "Algebraic topology: a first course"
|
|
57
|
+
expect(result.authors).to eq ["Greenberg, Marvin J."]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "returns nil when passed a blank string" do
|
|
62
|
+
result = described_class.marc_text_to_book("", described_class::USMARC_MAPPINGS)
|
|
63
|
+
expect(result).to be_nil
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "returns nil when passed nil" do
|
|
67
|
+
result = described_class.marc_text_to_book(nil, described_class::USMARC_MAPPINGS)
|
|
68
|
+
expect(result).to be_nil
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -27,10 +27,17 @@ describe Alexandria::Scanners::CueCat do
|
|
|
27
27
|
expect(cuecat.name).to match(/CueCat/i)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
it "
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
it "refuses to detect incomplete scans" do
|
|
31
|
+
aggregate_failures do
|
|
32
|
+
partials.each { |scan| expect(cuecat.match?(scan)).to be false }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "detects complete scans" do
|
|
37
|
+
aggregate_failures do
|
|
38
|
+
expect(cuecat.match?(scans[:isbn])).to be true
|
|
39
|
+
expect(cuecat.match?(scans[:ib5])).to be true
|
|
40
|
+
end
|
|
34
41
|
end
|
|
35
42
|
|
|
36
43
|
it "decodes ISBN barcodes" do
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This file is part of Alexandria.
|
|
4
|
+
#
|
|
5
|
+
# See the file README.md for authorship and licensing information.
|
|
6
|
+
|
|
7
|
+
require_relative "../../spec_helper"
|
|
8
|
+
|
|
9
|
+
describe Alexandria::Scanners::KeyboardWedge do
|
|
10
|
+
let(:scanner) { described_class.new }
|
|
11
|
+
let(:partials) do
|
|
12
|
+
["9",
|
|
13
|
+
"978057507",
|
|
14
|
+
"97805711471"]
|
|
15
|
+
end
|
|
16
|
+
let(:scans) do
|
|
17
|
+
{
|
|
18
|
+
isbn: "978 05711 47168",
|
|
19
|
+
ib5: "978057 5079038 007 99"
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "is called KeyboardWedge" do
|
|
24
|
+
expect(scanner.name).to match(/KeyboardWedge/i)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "refuses to detect incomplete scans" do
|
|
28
|
+
aggregate_failures do
|
|
29
|
+
partials.each { |scan| expect(scanner.match?(scan)).to be false }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "detects complete scans" do
|
|
34
|
+
aggregate_failures do
|
|
35
|
+
expect(scanner.match?(scans[:isbn])).to be true
|
|
36
|
+
expect(scanner.match?(scans[:ib5])).to be true
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "decodes ISBN barcodes" do
|
|
41
|
+
expect(scanner.decode(scans[:isbn])).to eq("9780571147168")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "decodes ISBN+5 barcodes" do
|
|
45
|
+
expect(scanner.decode(scans[:ib5])).to eq("9780575079038") # 00799
|
|
46
|
+
end
|
|
47
|
+
end
|