fb2rb 0.2.0 → 0.6.0
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 -0
- data/.github/workflows/ci.yml +6 -8
- data/.github/workflows/release.yml +4 -10
- data/CHANGELOG.adoc +21 -0
- data/README.adoc +19 -1
- data/fb2rb.gemspec +5 -4
- data/lib/fb2rb.rb +199 -148
- data/lib/fb2rb/version.rb +1 -1
- metadata +33 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49116036688f7932770da3cfd236c4d9d94ec45a2027983b2681d164c7ceea46
|
4
|
+
data.tar.gz: de234462849464702062f4da8c8a60b0b42fbc32e699de33ad392f594ddb3e9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 28a6f93d832c5d1f9927757a1efe21aeba51a68a4551bd79ceb15c99fb87254d32cef69436ff14b0296883c6c5bce882d89d34fc7087685bbb9003b439bedf61
|
7
|
+
data.tar.gz: dcad03884beee280cf6b4f64c8911bb70ef42fedb0b501d0a65676f8907c1edfeedd2673b827323464e06af929aba63b077e75608a984506bbbcb3deb529ecb3
|
data/.github/dependabot.yml
CHANGED
data/.github/workflows/ci.yml
CHANGED
@@ -9,17 +9,16 @@ jobs:
|
|
9
9
|
- name: Set up Ruby
|
10
10
|
uses: ruby/setup-ruby@v1
|
11
11
|
with:
|
12
|
-
ruby-version:
|
13
|
-
|
14
|
-
run: bundle install --jobs 4 --retry 3
|
12
|
+
ruby-version: '3.0'
|
13
|
+
bundler-cache: true
|
15
14
|
- name: Lint
|
16
15
|
run: bundle exec rake lint
|
17
16
|
test:
|
18
17
|
strategy:
|
19
18
|
matrix:
|
20
|
-
ruby: [jruby, 2.4, 2.5, 2.6, 2.7]
|
21
|
-
|
22
|
-
runs-on: ${{ matrix.
|
19
|
+
ruby: ['jruby', '2.4', '2.5', '2.6', '2.7', '3.0']
|
20
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
21
|
+
runs-on: ${{ matrix.os }}
|
23
22
|
steps:
|
24
23
|
- name: Checkout
|
25
24
|
uses: actions/checkout@v2
|
@@ -27,7 +26,6 @@ jobs:
|
|
27
26
|
uses: ruby/setup-ruby@v1
|
28
27
|
with:
|
29
28
|
ruby-version: ${{ matrix.ruby }}
|
30
|
-
|
31
|
-
run: bundle install --jobs 4 --retry 3
|
29
|
+
bundler-cache: true
|
32
30
|
- name: Test
|
33
31
|
run: bundle exec rake spec
|
@@ -11,14 +11,8 @@ jobs:
|
|
11
11
|
- name: Set up Ruby
|
12
12
|
uses: ruby/setup-ruby@v1
|
13
13
|
with:
|
14
|
-
ruby-version:
|
14
|
+
ruby-version: '3.0'
|
15
15
|
- name: Publish to RubyGems.org
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
chmod 0600 $HOME/.gem/credentials
|
20
|
-
printf -- "---\n:rubygems_api_key: ${RUBYGEMS_API_KEY}\n" > $HOME/.gem/credentials
|
21
|
-
gem build *.gemspec
|
22
|
-
gem push *.gem
|
23
|
-
env:
|
24
|
-
RUBYGEMS_API_KEY: ${{secrets.RUBYGEMS_API_KEY}}
|
16
|
+
uses: dawidd6/action-publish-gem@v1
|
17
|
+
with:
|
18
|
+
api_key: ${{ secrets.RUBYGEMS_API_KEY }}
|
data/CHANGELOG.adoc
CHANGED
@@ -7,6 +7,27 @@
|
|
7
7
|
This document provides a high-level view of the changes to the {project-name} by release.
|
8
8
|
For a detailed view of what has changed, refer to the {uri-project}/commits/master[commit history] on GitHub.
|
9
9
|
|
10
|
+
== 0.6.0 (2021-02-14) @slonopotamus
|
11
|
+
|
12
|
+
* Allow Nokogiri 1.11
|
13
|
+
|
14
|
+
== 0.5.0 (2020-12-07) - @slonopotamus
|
15
|
+
|
16
|
+
* return `nil` from `FB2rb::Book.read_compressed` for empty ZIP files
|
17
|
+
* **breaking change**: switch to named parameters instead of optional
|
18
|
+
|
19
|
+
== 0.4.0 (2020-11-24) - @slonopotamus
|
20
|
+
|
21
|
+
* add `Book::add_stylesheet` method
|
22
|
+
|
23
|
+
== 0.3.0 (2020-07-27) - @slonopotamus
|
24
|
+
|
25
|
+
* Support reading/writing uncompressed FB2. https://github.com/slonopotamus/fb2rb/issues/5[#5]
|
26
|
+
|
27
|
+
== 0.2.1 (2020-07-24) - @slonopotamus
|
28
|
+
|
29
|
+
* Fix field annotation on `FB2rb::TitleInfo::date`
|
30
|
+
|
10
31
|
== 0.2.0 (2020-07-24) - @slonopotamus
|
11
32
|
|
12
33
|
* Add support for reproducible builds
|
data/README.adoc
CHANGED
@@ -37,6 +37,8 @@ $ gem install fb2rb
|
|
37
37
|
|
38
38
|
== Usage
|
39
39
|
|
40
|
+
You can create FB2 book in memory and write it to file:
|
41
|
+
|
40
42
|
[source,ruby]
|
41
43
|
----
|
42
44
|
require 'fb2rb'
|
@@ -47,7 +49,23 @@ book.description.title_info.book_title = 'Book title'
|
|
47
49
|
body = FB2rb::Body.new(nil, '<p>Book text</p>')
|
48
50
|
book.bodies << body
|
49
51
|
|
50
|
-
book.
|
52
|
+
book.write_compressed('/path/to/book.fb2.zip')
|
53
|
+
# or
|
54
|
+
book.write_uncompressed('/path/to/book.fb2')
|
55
|
+
----
|
56
|
+
|
57
|
+
Also, you can read existing FB2 file:
|
58
|
+
|
59
|
+
[source,ruby]
|
60
|
+
----
|
61
|
+
require 'fb2rb'
|
62
|
+
|
63
|
+
book = FB2rb::Book.read_compressed('/path/to/book.fb2.zip')
|
64
|
+
# or
|
65
|
+
book = FB2rb::Book.read_uncompressed('/path/to/book.fb2')
|
66
|
+
|
67
|
+
puts book.description.title_info.book_title
|
68
|
+
puts book.bodies[0].content
|
51
69
|
----
|
52
70
|
|
53
71
|
== Development
|
data/fb2rb.gemspec
CHANGED
@@ -18,11 +18,12 @@ Gem::Specification.new do |s|
|
|
18
18
|
end
|
19
19
|
s.require_paths = ['lib']
|
20
20
|
|
21
|
-
s.add_runtime_dependency 'nokogiri', '
|
21
|
+
s.add_runtime_dependency 'nokogiri', '>= 1.10', '< 1.12'
|
22
22
|
s.add_runtime_dependency 'rubyzip', '~> 2.3.0'
|
23
23
|
|
24
24
|
s.add_development_dependency 'rake', '~> 13.0.0'
|
25
|
-
s.add_development_dependency 'rspec', '~> 3.
|
26
|
-
s.add_development_dependency 'rubocop', '~>
|
27
|
-
s.add_development_dependency 'rubocop-
|
25
|
+
s.add_development_dependency 'rspec', '~> 3.10.0'
|
26
|
+
s.add_development_dependency 'rubocop', '~> 1.9.0'
|
27
|
+
s.add_development_dependency 'rubocop-rake', '~> 0.5.0'
|
28
|
+
s.add_development_dependency 'rubocop-rspec', '~> 2.2.0'
|
28
29
|
end
|
data/lib/fb2rb.rb
CHANGED
@@ -12,7 +12,7 @@ module FB2rb
|
|
12
12
|
XLINK_NAMESPACE = 'http://www.w3.org/1999/xlink'
|
13
13
|
|
14
14
|
# Holds data of a single FB2 file
|
15
|
-
class Book
|
15
|
+
class Book # rubocop:disable Metrics/ClassLength
|
16
16
|
# @return [Array<FB2rb::Stylesheet>]
|
17
17
|
attr_accessor(:stylesheets)
|
18
18
|
# @return [FB2rb::Description]
|
@@ -22,47 +22,73 @@ module FB2rb
|
|
22
22
|
# @return [Array<FB2fb::Binary>]
|
23
23
|
attr_accessor(:binaries)
|
24
24
|
|
25
|
-
def initialize(description
|
25
|
+
def initialize(description: Description.new, bodies: [], binaries: [], stylesheets: [])
|
26
26
|
@binaries = binaries
|
27
27
|
@bodies = bodies
|
28
28
|
@description = description
|
29
29
|
@stylesheets = stylesheets
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
32
|
+
class << self
|
33
|
+
# Reads existing compressed FB2 file from an IO object, and creates new Book object.
|
34
|
+
# @return [FB2rb::Book, nil]
|
35
|
+
def read_compressed(filename_or_io)
|
36
|
+
Zip::InputStream.open(filename_or_io) do |zis|
|
37
|
+
while (entry = zis.get_next_entry)
|
38
|
+
next if entry.directory?
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
xml = Nokogiri::XML::Document.parse(zis)
|
41
|
+
fb2_prefix = ns_prefix(FB2rb::FB2_NAMESPACE, xml.namespaces)
|
42
|
+
xlink_prefix = ns_prefix(FB2rb::XLINK_NAMESPACE, xml.namespaces)
|
43
|
+
return parse(xml, fb2_prefix, xlink_prefix)
|
44
|
+
end
|
43
45
|
end
|
46
|
+
nil
|
44
47
|
end
|
45
|
-
end
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
49
|
+
# Reads existing uncompressed FB2 file from an IO object, and creates new Book object.
|
50
|
+
# @return [FB2rb::Book]
|
51
|
+
def read_uncompressed(filename_or_io)
|
52
|
+
xml = read_xml(filename_or_io)
|
53
|
+
fb2_prefix = ns_prefix(FB2rb::FB2_NAMESPACE, xml.namespaces)
|
54
|
+
xlink_prefix = ns_prefix(FB2rb::XLINK_NAMESPACE, xml.namespaces)
|
55
|
+
parse(xml, fb2_prefix, xlink_prefix)
|
56
|
+
end
|
51
57
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
58
|
+
def ns_prefix(namespace, namespaces)
|
59
|
+
prefix = namespaces.key(namespace)
|
60
|
+
prefix.nil? ? nil : prefix.sub(/^xmlns:/, '')
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
# @return [FB2rb::Book]
|
66
|
+
def parse(xml, fb2_prefix, xlink_prefix) # rubocop:disable Metrics/MethodLength
|
67
|
+
Book.new(
|
68
|
+
description: Description.parse(
|
69
|
+
xml.xpath("/#{fb2_prefix}:FictionBook/#{fb2_prefix}:description"), fb2_prefix, xlink_prefix
|
70
|
+
),
|
71
|
+
bodies: xml.xpath("/#{fb2_prefix}:FictionBook/#{fb2_prefix}:body").map do |node|
|
72
|
+
Body.parse(node)
|
73
|
+
end,
|
74
|
+
binaries: xml.xpath("#{fb2_prefix}:FictionBook/#{fb2_prefix}:binary").map do |node|
|
75
|
+
Binary.parse(node)
|
76
|
+
end,
|
77
|
+
stylesheets: xml.xpath("/#{fb2_prefix}:FictionBook/#{fb2_prefix}:stylesheet").map do |node|
|
78
|
+
Stylesheet.parse(node)
|
79
|
+
end
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
def read_xml(filename_or_io)
|
84
|
+
if filename_or_io.respond_to? :read
|
85
|
+
Nokogiri::XML::Document.parse(filename_or_io)
|
86
|
+
else
|
87
|
+
File.open(filename_or_io, 'rb') do |io|
|
88
|
+
return Nokogiri::XML::Document.parse(io)
|
89
|
+
end
|
64
90
|
end
|
65
|
-
|
91
|
+
end
|
66
92
|
end
|
67
93
|
|
68
94
|
def to_xml(xml) # rubocop:disable Metrics/MethodLength
|
@@ -81,18 +107,28 @@ module FB2rb
|
|
81
107
|
end
|
82
108
|
end
|
83
109
|
|
84
|
-
def add_binary(
|
110
|
+
def add_binary(id, filename_or_io, content_type = nil)
|
111
|
+
if filename_or_io.respond_to?(:read)
|
112
|
+
add_binary_io id, filename_or_io, content_type
|
113
|
+
else
|
114
|
+
File.open(filename_or_io, 'r') do |io|
|
115
|
+
add_binary_io id, io, content_type
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def add_stylesheet(content_type, filename_or_io)
|
85
121
|
if filename_or_io.respond_to?(:read)
|
86
|
-
|
122
|
+
add_stylesheet_io(content_type, filename_or_io)
|
87
123
|
else
|
88
124
|
File.open(filename_or_io, 'r') do |io|
|
89
|
-
|
125
|
+
add_stylesheet_io(content_type, io)
|
90
126
|
end
|
91
127
|
end
|
92
128
|
end
|
93
129
|
|
94
|
-
# Writes FB2 to file or IO object. If file exists, it will be overwritten.
|
95
|
-
def
|
130
|
+
# Writes compressed FB2 to file or IO object. If file exists, it will be overwritten.
|
131
|
+
def write_compressed(filename_or_io = StringIO.new)
|
96
132
|
if filename_or_io.respond_to?(:write)
|
97
133
|
Zip::OutputStream.write_buffer(filename_or_io) do |zos|
|
98
134
|
write_to_zip(zos)
|
@@ -104,6 +140,22 @@ module FB2rb
|
|
104
140
|
end
|
105
141
|
end
|
106
142
|
|
143
|
+
# Writes FB2 (uncompressed) to file or IO object specified by the argument.
|
144
|
+
def write_uncompressed(filename_or_io = StringIO.new) # rubocop:disable Metrics/MethodLength
|
145
|
+
data = (Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
146
|
+
to_xml(xml)
|
147
|
+
end).to_xml
|
148
|
+
|
149
|
+
if filename_or_io.respond_to?(:write)
|
150
|
+
filename_or_io.write(data)
|
151
|
+
else
|
152
|
+
File.open(filename_or_io, 'wb') do |io|
|
153
|
+
io.write(data)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
filename_or_io
|
157
|
+
end
|
158
|
+
|
107
159
|
private
|
108
160
|
|
109
161
|
def write_to_zip(zos)
|
@@ -115,23 +167,21 @@ module FB2rb
|
|
115
167
|
# TODO: entry name
|
116
168
|
mimetype_entry = Zip::Entry.new(nil, 'book.fb2', nil, nil, nil, nil, nil, nil, mod_time)
|
117
169
|
zos.put_next_entry(mimetype_entry, nil, nil, Zip::Entry::DEFLATED)
|
118
|
-
|
170
|
+
write_uncompressed(zos)
|
119
171
|
end
|
120
172
|
|
121
|
-
def add_binary_io(
|
173
|
+
def add_binary_io(id, io, content_type = nil)
|
122
174
|
io.binmode
|
123
175
|
content = io.read
|
124
|
-
@binaries << Binary.new(
|
176
|
+
@binaries << Binary.new(id: id, content: content, content_type: content_type)
|
125
177
|
self
|
126
178
|
end
|
127
179
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
xml = builder.to_xml
|
134
|
-
io.write(xml)
|
180
|
+
def add_stylesheet_io(content_type, io)
|
181
|
+
io.binmode
|
182
|
+
content = io.read
|
183
|
+
@stylesheets << Stylesheet.new(content_type: content_type, content: content)
|
184
|
+
self
|
135
185
|
end
|
136
186
|
end
|
137
187
|
|
@@ -147,13 +197,14 @@ module FB2rb
|
|
147
197
|
attr_accessor(:publish_info)
|
148
198
|
# @return [Array<FB2rb::CustomInfo>]
|
149
199
|
attr_accessor(:custom_infos)
|
200
|
+
|
150
201
|
# TODO: <output>
|
151
202
|
|
152
|
-
def initialize(title_info
|
153
|
-
document_info
|
154
|
-
publish_info
|
155
|
-
src_title_info
|
156
|
-
custom_infos
|
203
|
+
def initialize(title_info: TitleInfo.new,
|
204
|
+
document_info: DocumentInfo.new,
|
205
|
+
publish_info: nil,
|
206
|
+
src_title_info: nil,
|
207
|
+
custom_infos: [])
|
157
208
|
@title_info = title_info
|
158
209
|
@document_info = document_info
|
159
210
|
@publish_info = publish_info
|
@@ -166,11 +217,11 @@ module FB2rb
|
|
166
217
|
publish_info_xml = xml.at("./#{fb2_prefix}:publish-info")
|
167
218
|
src_title_info_xml = xml.at("./#{fb2_prefix}:src-title-info")
|
168
219
|
Description.new(
|
169
|
-
TitleInfo.parse(xml.at("./#{fb2_prefix}:title-info"), fb2_prefix, xlink_prefix),
|
170
|
-
DocumentInfo.parse(xml.at("./#{fb2_prefix}:document-info"), fb2_prefix),
|
171
|
-
publish_info_xml.nil? ? nil : PublishInfo.parse(publish_info_xml, fb2_prefix),
|
172
|
-
src_title_info_xml.nil? ? nil : TitleInfo.parse(src_title_info_xml, fb2_prefix, xlink_prefix),
|
173
|
-
xml.xpath("./#{fb2_prefix}:custom-info").map do |node|
|
220
|
+
title_info: TitleInfo.parse(xml.at("./#{fb2_prefix}:title-info"), fb2_prefix, xlink_prefix),
|
221
|
+
document_info: DocumentInfo.parse(xml.at("./#{fb2_prefix}:document-info"), fb2_prefix),
|
222
|
+
publish_info: publish_info_xml.nil? ? nil : PublishInfo.parse(publish_info_xml, fb2_prefix),
|
223
|
+
src_title_info: src_title_info_xml.nil? ? nil : TitleInfo.parse(src_title_info_xml, fb2_prefix, xlink_prefix),
|
224
|
+
custom_infos: xml.xpath("./#{fb2_prefix}:custom-info").map do |node|
|
174
225
|
CustomInfo.parse(node)
|
175
226
|
end
|
176
227
|
)
|
@@ -192,47 +243,47 @@ module FB2rb
|
|
192
243
|
# Holds <stylesheet> data
|
193
244
|
class Stylesheet
|
194
245
|
# @return [String]
|
195
|
-
attr_accessor(:
|
246
|
+
attr_accessor(:content_type)
|
196
247
|
# @return [String, nil]
|
197
248
|
attr_accessor(:content)
|
198
249
|
|
199
|
-
def initialize(
|
200
|
-
@
|
250
|
+
def initialize(content_type: '', content: nil)
|
251
|
+
@content_type = content_type
|
201
252
|
@content = content
|
202
253
|
end
|
203
254
|
|
204
255
|
def self.parse(xml)
|
205
|
-
Stylesheet.new(xml['type'], xml.text)
|
256
|
+
Stylesheet.new(content_type: xml['type'], content: xml.text)
|
206
257
|
end
|
207
258
|
|
208
259
|
def to_xml(xml)
|
209
260
|
return if @content.nil?
|
210
261
|
|
211
|
-
xml.send('stylesheet', @content, 'type' => @
|
262
|
+
xml.send('stylesheet', @content, 'type' => @content_type)
|
212
263
|
end
|
213
264
|
end
|
214
265
|
|
215
266
|
# Holds <custom-info> data
|
216
267
|
class CustomInfo
|
217
268
|
# @return [String]
|
218
|
-
attr_accessor(:
|
269
|
+
attr_accessor(:type)
|
219
270
|
# @return [String, nil]
|
220
271
|
attr_accessor(:content)
|
221
272
|
|
222
|
-
def initialize(
|
223
|
-
@
|
273
|
+
def initialize(type: '', content: nil)
|
274
|
+
@type = type
|
224
275
|
@content = content
|
225
276
|
end
|
226
277
|
|
227
278
|
# @return [FB2rb::CustomInfo]
|
228
279
|
def self.parse(xml)
|
229
|
-
CustomInfo.new(xml['info-type'], xml.text)
|
280
|
+
CustomInfo.new(type: xml['info-type'], content: xml.text)
|
230
281
|
end
|
231
282
|
|
232
283
|
def to_xml(xml)
|
233
284
|
return if @content.nil?
|
234
285
|
|
235
|
-
xml.send('custom-info', @content, 'info-type' => @
|
286
|
+
xml.send('custom-info', @content, 'info-type' => @type)
|
236
287
|
end
|
237
288
|
end
|
238
289
|
|
@@ -251,12 +302,12 @@ module FB2rb
|
|
251
302
|
# @return [Array<FB2RB::Sequence>]
|
252
303
|
attr_accessor(:sequences)
|
253
304
|
|
254
|
-
def initialize(book_name
|
255
|
-
publisher
|
256
|
-
city
|
257
|
-
year
|
258
|
-
isbn
|
259
|
-
sequences
|
305
|
+
def initialize(book_name: nil, # rubocop:disable Metrics/ParameterLists
|
306
|
+
publisher: nil,
|
307
|
+
city: nil,
|
308
|
+
year: nil,
|
309
|
+
isbn: nil,
|
310
|
+
sequences: [])
|
260
311
|
@book_name = book_name
|
261
312
|
@publisher = publisher
|
262
313
|
@city = city
|
@@ -268,12 +319,12 @@ module FB2rb
|
|
268
319
|
# @return [FB2RB::PublishInfo]
|
269
320
|
def self.parse(xml, fb2_prefix)
|
270
321
|
PublishInfo.new(
|
271
|
-
xml.at("./#{fb2_prefix}:book-name/text()")&.text,
|
272
|
-
xml.at("./#{fb2_prefix}:publisher/text()")&.text,
|
273
|
-
xml.at("./#{fb2_prefix}:city/text()")&.text,
|
274
|
-
xml.at("./#{fb2_prefix}:year/text()")&.text,
|
275
|
-
xml.at("./#{fb2_prefix}:isbn/text()")&.text,
|
276
|
-
xml.xpath("./#{fb2_prefix}:sequence").map do |node|
|
322
|
+
book_name: xml.at("./#{fb2_prefix}:book-name/text()")&.text,
|
323
|
+
publisher: xml.at("./#{fb2_prefix}:publisher/text()")&.text,
|
324
|
+
city: xml.at("./#{fb2_prefix}:city/text()")&.text,
|
325
|
+
year: xml.at("./#{fb2_prefix}:year/text()")&.text,
|
326
|
+
isbn: xml.at("./#{fb2_prefix}:isbn/text()")&.text,
|
327
|
+
sequences: xml.xpath("./#{fb2_prefix}:sequence").map do |node|
|
277
328
|
Sequence.parse(node)
|
278
329
|
end
|
279
330
|
)
|
@@ -314,15 +365,15 @@ module FB2rb
|
|
314
365
|
# @return [Array<String>]
|
315
366
|
attr_accessor(:publishers)
|
316
367
|
|
317
|
-
def initialize(authors
|
318
|
-
program_used
|
319
|
-
date
|
320
|
-
src_urls
|
321
|
-
src_ocr
|
322
|
-
id
|
323
|
-
version
|
324
|
-
history
|
325
|
-
publishers
|
368
|
+
def initialize(authors: [], # rubocop:disable Metrics/ParameterLists
|
369
|
+
program_used: nil,
|
370
|
+
date: FB2Date.new,
|
371
|
+
src_urls: [],
|
372
|
+
src_ocr: nil,
|
373
|
+
id: '',
|
374
|
+
version: '',
|
375
|
+
history: nil,
|
376
|
+
publishers: [])
|
326
377
|
@authors = authors
|
327
378
|
@program_used = program_used
|
328
379
|
@date = date
|
@@ -335,20 +386,20 @@ module FB2rb
|
|
335
386
|
end
|
336
387
|
|
337
388
|
# @return [FB2rb::DocumentInfo]
|
338
|
-
def self.parse(xml, fb2_prefix) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
389
|
+
def self.parse(xml, fb2_prefix) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
339
390
|
date = xml.at("./#{fb2_prefix}:date")
|
340
391
|
DocumentInfo.new(
|
341
|
-
xml.xpath("./#{fb2_prefix}:author").map do |node|
|
392
|
+
authors: xml.xpath("./#{fb2_prefix}:author").map do |node|
|
342
393
|
Author.parse(node, fb2_prefix)
|
343
394
|
end,
|
344
|
-
xml.at("./#{fb2_prefix}:program-used")&.text,
|
345
|
-
date.nil? ? FB2Date.new : FB2Date.parse(date),
|
346
|
-
xml.xpath("./#{fb2_prefix}:src-url").map(&:text),
|
347
|
-
xml.at("./#{fb2_prefix}:src-ocr")&.text,
|
348
|
-
xml.at("./#{fb2_prefix}:id").text,
|
349
|
-
xml.at("./#{fb2_prefix}:version")&.text,
|
350
|
-
xml.at("./#{fb2_prefix}:history")&.children&.to_s&.strip,
|
351
|
-
xml.xpath("./#{fb2_prefix}:publisher").map(&:text)
|
395
|
+
program_used: xml.at("./#{fb2_prefix}:program-used")&.text,
|
396
|
+
date: date.nil? ? FB2Date.new : FB2Date.parse(date),
|
397
|
+
src_urls: xml.xpath("./#{fb2_prefix}:src-url").map(&:text),
|
398
|
+
src_ocr: xml.at("./#{fb2_prefix}:src-ocr")&.text,
|
399
|
+
id: xml.at("./#{fb2_prefix}:id").text,
|
400
|
+
version: xml.at("./#{fb2_prefix}:version")&.text,
|
401
|
+
history: xml.at("./#{fb2_prefix}:history")&.children&.to_s&.strip,
|
402
|
+
publishers: xml.xpath("./#{fb2_prefix}:publisher").map(&:text)
|
352
403
|
)
|
353
404
|
end
|
354
405
|
|
@@ -389,7 +440,7 @@ module FB2rb
|
|
389
440
|
attr_accessor(:annotation)
|
390
441
|
# @return [Array<String>]
|
391
442
|
attr_accessor(:keywords)
|
392
|
-
# @return [
|
443
|
+
# @return [FB2rb::Date, nil]
|
393
444
|
attr_accessor(:date)
|
394
445
|
# @return [FB2rb::Coverpage, nil]
|
395
446
|
attr_accessor(:coverpage)
|
@@ -402,17 +453,17 @@ module FB2rb
|
|
402
453
|
# @return [Array<FB2rb::Sequence>]
|
403
454
|
attr_accessor(:sequences)
|
404
455
|
|
405
|
-
def initialize(genres
|
406
|
-
authors
|
407
|
-
book_title
|
408
|
-
annotation
|
409
|
-
keywords
|
410
|
-
date
|
411
|
-
coverpage
|
412
|
-
lang
|
413
|
-
src_lang
|
414
|
-
translators
|
415
|
-
sequences
|
456
|
+
def initialize(genres: [], # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
|
457
|
+
authors: [],
|
458
|
+
book_title: '',
|
459
|
+
annotation: nil,
|
460
|
+
keywords: [],
|
461
|
+
date: nil,
|
462
|
+
coverpage: nil,
|
463
|
+
lang: 'en',
|
464
|
+
src_lang: nil,
|
465
|
+
translators: [],
|
466
|
+
sequences: [])
|
416
467
|
@genres = genres
|
417
468
|
@authors = authors
|
418
469
|
@book_title = book_title
|
@@ -427,31 +478,31 @@ module FB2rb
|
|
427
478
|
end
|
428
479
|
|
429
480
|
# @return [FB2rb::TitleInfo]
|
430
|
-
def self.parse(xml, fb2_prefix, xlink_prefix) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
481
|
+
def self.parse(xml, fb2_prefix, xlink_prefix) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
431
482
|
date = xml.at("./#{fb2_prefix}:date")
|
432
483
|
coverpage = xml.at("./#{fb2_prefix}:coverpage")
|
433
484
|
TitleInfo.new(
|
434
|
-
xml.xpath("./#{fb2_prefix}:genre/text()").map(&:text),
|
435
|
-
xml.xpath("./#{fb2_prefix}:author").map do |node|
|
485
|
+
genres: xml.xpath("./#{fb2_prefix}:genre/text()").map(&:text),
|
486
|
+
authors: xml.xpath("./#{fb2_prefix}:author").map do |node|
|
436
487
|
Author.parse(node, fb2_prefix)
|
437
488
|
end,
|
438
|
-
xml.at("./#{fb2_prefix}:book-title/text()")&.text,
|
439
|
-
xml.at("./#{fb2_prefix}:annotation")&.children.to_s.strip,
|
440
|
-
xml.at("./#{fb2_prefix}:keywords/text()")&.text&.split(', ') || [],
|
441
|
-
date.nil? ? nil : FB2Date.parse(date),
|
442
|
-
coverpage.nil? ? nil : Coverpage.parse(coverpage, fb2_prefix, xlink_prefix),
|
443
|
-
xml.at("./#{fb2_prefix}:lang/text()").text,
|
444
|
-
xml.at("./#{fb2_prefix}:src-lang/text()")&.text,
|
445
|
-
xml.xpath("./#{fb2_prefix}:translator").map do |node|
|
489
|
+
book_title: xml.at("./#{fb2_prefix}:book-title/text()")&.text,
|
490
|
+
annotation: xml.at("./#{fb2_prefix}:annotation")&.children.to_s.strip,
|
491
|
+
keywords: xml.at("./#{fb2_prefix}:keywords/text()")&.text&.split(', ') || [],
|
492
|
+
date: date.nil? ? nil : FB2Date.parse(date),
|
493
|
+
coverpage: coverpage.nil? ? nil : Coverpage.parse(coverpage, fb2_prefix, xlink_prefix),
|
494
|
+
lang: xml.at("./#{fb2_prefix}:lang/text()").text,
|
495
|
+
src_lang: xml.at("./#{fb2_prefix}:src-lang/text()")&.text,
|
496
|
+
translators: xml.xpath("./#{fb2_prefix}:translator").map do |node|
|
446
497
|
Author.parse(node, fb2_prefix)
|
447
498
|
end,
|
448
|
-
xml.xpath("./#{fb2_prefix}:sequence").map do |node|
|
499
|
+
sequences: xml.xpath("./#{fb2_prefix}:sequence").map do |node|
|
449
500
|
Sequence.parse(node)
|
450
501
|
end
|
451
502
|
)
|
452
503
|
end
|
453
504
|
|
454
|
-
def to_xml(xml, tag) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
505
|
+
def to_xml(xml, tag) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
455
506
|
xml.send(tag) do
|
456
507
|
genres.each do |genre|
|
457
508
|
xml.genre(genre)
|
@@ -485,13 +536,13 @@ module FB2rb
|
|
485
536
|
# @return [Array<String>]
|
486
537
|
attr_accessor(:images)
|
487
538
|
|
488
|
-
def initialize(images
|
539
|
+
def initialize(images: [])
|
489
540
|
@images = images
|
490
541
|
end
|
491
542
|
|
492
543
|
def self.parse(xml, fb2_prefix, xlink_prefix)
|
493
544
|
Coverpage.new(
|
494
|
-
xml.xpath("./#{fb2_prefix}:image/@#{xlink_prefix}:href").map(&:to_s)
|
545
|
+
images: xml.xpath("./#{fb2_prefix}:image/@#{xlink_prefix}:href").map(&:to_s)
|
495
546
|
)
|
496
547
|
end
|
497
548
|
|
@@ -511,7 +562,7 @@ module FB2rb
|
|
511
562
|
# @return [Date, nil]
|
512
563
|
attr_accessor(:value)
|
513
564
|
|
514
|
-
def initialize(display_value
|
565
|
+
def initialize(display_value: '', value: nil)
|
515
566
|
@display_value = display_value
|
516
567
|
@value = value
|
517
568
|
end
|
@@ -519,8 +570,8 @@ module FB2rb
|
|
519
570
|
def self.parse(xml)
|
520
571
|
value = xml['value']
|
521
572
|
FB2Date.new(
|
522
|
-
xml.at('./text()')&.text || '',
|
523
|
-
value.nil? ? nil : Date.parse(value)
|
573
|
+
display_value: xml.at('./text()')&.text || '',
|
574
|
+
value: value.nil? ? nil : Date.parse(value)
|
524
575
|
)
|
525
576
|
end
|
526
577
|
|
@@ -538,14 +589,14 @@ module FB2rb
|
|
538
589
|
# @return [Integer, nil]
|
539
590
|
attr_accessor(:number)
|
540
591
|
|
541
|
-
def initialize(name
|
592
|
+
def initialize(name: '', number: nil)
|
542
593
|
@name = name
|
543
594
|
@number = number
|
544
595
|
end
|
545
596
|
|
546
597
|
# @return [FB2rb::Sequence]
|
547
598
|
def self.parse(xml)
|
548
|
-
Sequence.new(xml['name'], xml['number']&.to_i)
|
599
|
+
Sequence.new(name: xml['name'], number: xml['number']&.to_i)
|
549
600
|
end
|
550
601
|
|
551
602
|
def to_xml(xml)
|
@@ -572,13 +623,13 @@ module FB2rb
|
|
572
623
|
# @return [String, nil]
|
573
624
|
attr_accessor(:id)
|
574
625
|
|
575
|
-
def initialize(first_name
|
576
|
-
middle_name
|
577
|
-
last_name
|
578
|
-
nickname
|
579
|
-
home_pages
|
580
|
-
emails
|
581
|
-
id
|
626
|
+
def initialize(first_name: nil, # rubocop:disable Metrics/ParameterLists
|
627
|
+
middle_name: nil,
|
628
|
+
last_name: nil,
|
629
|
+
nickname: nil,
|
630
|
+
home_pages: [],
|
631
|
+
emails: [],
|
632
|
+
id: nil)
|
582
633
|
@first_name = first_name
|
583
634
|
@middle_name = middle_name
|
584
635
|
@last_name = last_name
|
@@ -591,17 +642,17 @@ module FB2rb
|
|
591
642
|
# @return [FB2rb::Author]
|
592
643
|
def self.parse(xml, fb2_prefix) # rubocop:disable Metrics/CyclomaticComplexity
|
593
644
|
Author.new(
|
594
|
-
xml.at("./#{fb2_prefix}:first-name/text()")&.text,
|
595
|
-
xml.at("./#{fb2_prefix}:middle-name/text()")&.text,
|
596
|
-
xml.at("./#{fb2_prefix}:last-name/text()")&.text,
|
597
|
-
xml.at("./#{fb2_prefix}:nickname/text()")&.text,
|
598
|
-
xml.xpath("./#{fb2_prefix}:home-page/text()").map(&:text),
|
599
|
-
xml.xpath("./#{fb2_prefix}:email/text()").map(&:text),
|
600
|
-
xml.at("./#{fb2_prefix}:id/text()")&.text
|
645
|
+
first_name: xml.at("./#{fb2_prefix}:first-name/text()")&.text,
|
646
|
+
middle_name: xml.at("./#{fb2_prefix}:middle-name/text()")&.text,
|
647
|
+
last_name: xml.at("./#{fb2_prefix}:last-name/text()")&.text,
|
648
|
+
nickname: xml.at("./#{fb2_prefix}:nickname/text()")&.text,
|
649
|
+
home_pages: xml.xpath("./#{fb2_prefix}:home-page/text()").map(&:text),
|
650
|
+
emails: xml.xpath("./#{fb2_prefix}:email/text()").map(&:text),
|
651
|
+
id: xml.at("./#{fb2_prefix}:id/text()")&.text
|
601
652
|
)
|
602
653
|
end
|
603
654
|
|
604
|
-
def to_xml(xml, tag) # rubocop:disable Metrics/
|
655
|
+
def to_xml(xml, tag) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
605
656
|
xml.send(tag) do
|
606
657
|
xml.send('first-name', @first_name) unless @first_name.nil?
|
607
658
|
xml.send('middle-name', @middle_name) unless @middle_name.nil?
|
@@ -625,7 +676,7 @@ module FB2rb
|
|
625
676
|
# @return [String]
|
626
677
|
attr_accessor(:content)
|
627
678
|
|
628
|
-
def initialize(name
|
679
|
+
def initialize(name: nil, content: '')
|
629
680
|
@name = name
|
630
681
|
@content = content
|
631
682
|
end
|
@@ -633,8 +684,8 @@ module FB2rb
|
|
633
684
|
# @return [FB2rb::Body]
|
634
685
|
def self.parse(xml)
|
635
686
|
Body.new(
|
636
|
-
xml['name'],
|
637
|
-
xml.children.to_s.strip
|
687
|
+
name: xml['name'],
|
688
|
+
content: xml.children.to_s.strip
|
638
689
|
)
|
639
690
|
end
|
640
691
|
|
@@ -657,7 +708,7 @@ module FB2rb
|
|
657
708
|
# @return [String, nil]
|
658
709
|
attr_accessor(:content_type)
|
659
710
|
|
660
|
-
def initialize(id, content, content_type
|
711
|
+
def initialize(id: nil, content: ''.b, content_type: nil)
|
661
712
|
@id = id
|
662
713
|
@content = content
|
663
714
|
@content_type = content_type
|
@@ -665,7 +716,7 @@ module FB2rb
|
|
665
716
|
|
666
717
|
def self.parse(xml)
|
667
718
|
decoded = Base64.decode64(xml.text)
|
668
|
-
Binary.new(xml['id'], decoded, xml['content-type'])
|
719
|
+
Binary.new(id: xml['id'], content: decoded, content_type: xml['content-type'])
|
669
720
|
end
|
670
721
|
|
671
722
|
def to_xml(xml)
|
data/lib/fb2rb/version.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fb2rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marat Radchenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.10'
|
20
|
+
- - "<"
|
18
21
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
22
|
+
version: '1.12'
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
|
-
- - "
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.10'
|
30
|
+
- - "<"
|
25
31
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
32
|
+
version: '1.12'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: rubyzip
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,42 +64,56 @@ dependencies:
|
|
58
64
|
requirements:
|
59
65
|
- - "~>"
|
60
66
|
- !ruby/object:Gem::Version
|
61
|
-
version: 3.
|
67
|
+
version: 3.10.0
|
62
68
|
type: :development
|
63
69
|
prerelease: false
|
64
70
|
version_requirements: !ruby/object:Gem::Requirement
|
65
71
|
requirements:
|
66
72
|
- - "~>"
|
67
73
|
- !ruby/object:Gem::Version
|
68
|
-
version: 3.
|
74
|
+
version: 3.10.0
|
69
75
|
- !ruby/object:Gem::Dependency
|
70
76
|
name: rubocop
|
71
77
|
requirement: !ruby/object:Gem::Requirement
|
72
78
|
requirements:
|
73
79
|
- - "~>"
|
74
80
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
81
|
+
version: 1.9.0
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 1.9.0
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: rubocop-rake
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 0.5.0
|
76
96
|
type: :development
|
77
97
|
prerelease: false
|
78
98
|
version_requirements: !ruby/object:Gem::Requirement
|
79
99
|
requirements:
|
80
100
|
- - "~>"
|
81
101
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0.
|
102
|
+
version: 0.5.0
|
83
103
|
- !ruby/object:Gem::Dependency
|
84
104
|
name: rubocop-rspec
|
85
105
|
requirement: !ruby/object:Gem::Requirement
|
86
106
|
requirements:
|
87
107
|
- - "~>"
|
88
108
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
109
|
+
version: 2.2.0
|
90
110
|
type: :development
|
91
111
|
prerelease: false
|
92
112
|
version_requirements: !ruby/object:Gem::Requirement
|
93
113
|
requirements:
|
94
114
|
- - "~>"
|
95
115
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
116
|
+
version: 2.2.0
|
97
117
|
description:
|
98
118
|
email:
|
99
119
|
- marat@slonopotamus.org
|
@@ -139,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
159
|
- !ruby/object:Gem::Version
|
140
160
|
version: '0'
|
141
161
|
requirements: []
|
142
|
-
rubygems_version: 3.
|
162
|
+
rubygems_version: 3.2.3
|
143
163
|
signing_key:
|
144
164
|
specification_version: 4
|
145
165
|
summary: Fiction Book 2 parser/generator library
|