epub-parser 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/CHANGELOG.markdown +5 -0
- data/README.markdown +7 -25
- data/Rakefile +2 -10
- data/docs/Home.markdown +2 -1
- data/epub-parser.gemspec +1 -1
- data/examples/exctract-content-using-cfi.rb +1 -1
- data/examples/find-elements-and-cfis.rb +1 -1
- data/lib/epub/parser/version.rb +1 -1
- data/lib/epub/searcher/result.rb +0 -1
- data/test/test_searcher.rb +7 -7
- metadata +17 -13
- data/.gitmodules +0 -3
- data/.travis.yml +0 -4
- data/lib/epub/cfi.rb +0 -313
- data/lib/epub/parser/cfi.rb +0 -85
- data/lib/epub/parser/cfi.y +0 -187
- data/test/test_cfi.rb +0 -227
- data/test/test_parser_cfi.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0061ced06336ffbf3bcdeecdd56d91dd92d7dc01
|
4
|
+
data.tar.gz: 0ff0efba6754a25c31550f318f60041591e67729
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6fa942fad606d5722c09abac9caac938c3b364a3c44707940493a3aa7838ec2b6cb740bf696fbfb41c212fce44cb51d16b8ba919d4b1cd2bb72ce77a8b3f47be
|
7
|
+
data.tar.gz: ca69eb60e0ce44329c276eb3d33b6e3f564ac8432570fce70a0131dcbc2635a651249c2009d64417857bdd1c7bd4fd1bbb239b800b9574b1dff5329c6e5418db
|
data/.gitignore
CHANGED
data/CHANGELOG.markdown
CHANGED
data/README.markdown
CHANGED
@@ -134,7 +134,7 @@ Then documentation will be available in `doc` directory.
|
|
134
134
|
|
135
135
|
REQUIREMENTS
|
136
136
|
------------
|
137
|
-
* Ruby 2.
|
137
|
+
* Ruby 2.2.0 or later
|
138
138
|
* `patch` command to install Nokogiri
|
139
139
|
* C compiler to compile Nokogiri
|
140
140
|
|
@@ -145,13 +145,18 @@ Similar Efforts
|
|
145
145
|
* [ReVIEW](https://github.com/kmuto/review) - ReVIEW is a easy-to-use digital publishing system for books and ebooks.
|
146
146
|
* [epzip](https://github.com/takahashim/epzip) - epzip is EPUB packing tool. It's just only doing 'zip.' :)
|
147
147
|
* [eeepub](https://github.com/jugyo/eeepub) - EeePub is a Ruby ePub generator
|
148
|
-
* [epub-maker](https://
|
148
|
+
* [epub-maker](https://gitlab.com/KitaitiMakoto/epub-maker) - This library supports making and editing EPUB books based on this EPUB Parser library
|
149
|
+
* [epub-cfi](https://gitlab.com/KitaitiMakoto/epub-cfi) - EPUB CFI library extracted this EPUB Parser library.
|
149
150
|
|
150
151
|
If you find other gems, please tell me or request a pull request.
|
151
152
|
|
152
153
|
RECENT CHANGES
|
153
154
|
--------------
|
154
155
|
|
156
|
+
### 0.3.2
|
157
|
+
|
158
|
+
* Use epub-cfi gem for EPUB CFI
|
159
|
+
|
155
160
|
### 0.3.1
|
156
161
|
|
157
162
|
* Make `CFI` comparable. Now can call `CFI#==`
|
@@ -166,29 +171,6 @@ RECENT CHANGES
|
|
166
171
|
* Fix a bug that `Searcher.search_element` returns wrong CFI
|
167
172
|
* Add `Searcher.search_by_cfi`
|
168
173
|
|
169
|
-
### 0.2.8
|
170
|
-
|
171
|
-
* Change Searcher API: #search -> #search_text
|
172
|
-
* Add Searcher.search_element
|
173
|
-
|
174
|
-
### 0.2.7
|
175
|
-
|
176
|
-
* Add `EPUB::Metadata#children`
|
177
|
-
* Allow class including `EPUB` to intialize with extra arguments(Thanks, [skukx][]!)
|
178
|
-
|
179
|
-
[skukx]: https://github.com/skukx
|
180
|
-
|
181
|
-
### 0.2.6
|
182
|
-
|
183
|
-
* Add `EPUB::Publication::Package::Metadata#package_identifier` as alias of `#release_identifier`
|
184
|
-
* [BUG FIX]Metadata#modified returns modified with no refiners
|
185
|
-
* Make second argument for `EPUB::Parser::Publication.new` deprecated
|
186
|
-
* Add META-INF/metadata.xml support defined in [EPUB Multiple-Rendition Publications 1.0][multi-rendition]
|
187
|
-
* Add `EPUB::Book::Features#packages` and `#default_rendition`
|
188
|
-
* [BUG FIX]Don't raise error when using `Zipruby` container adapter
|
189
|
-
|
190
|
-
[multi-rendition]: http://www.idpf.org/epub/renditions/multiple/
|
191
|
-
|
192
174
|
See {file:CHANGELOG.markdown} for older changelogs and details.
|
193
175
|
|
194
176
|
TODOS
|
data/Rakefile
CHANGED
@@ -6,17 +6,9 @@ require 'rdoc/task'
|
|
6
6
|
require 'epub/parser/version'
|
7
7
|
require 'zipruby'
|
8
8
|
|
9
|
-
CFI_TAB = 'lib/epub/parser/cfi.tab.rb'
|
10
|
-
CFI_Y = 'lib/epub/parser/cfi.y'
|
11
|
-
CLEAN.include(CFI_TAB)
|
12
|
-
|
13
9
|
task :default => :test
|
14
10
|
task :test => 'test:default'
|
15
11
|
|
16
|
-
file CFI_TAB do
|
17
|
-
sh "racc #{CFI_Y}"
|
18
|
-
end
|
19
|
-
|
20
12
|
namespace :test do
|
21
13
|
task :default => [:build, :test]
|
22
14
|
|
@@ -24,7 +16,7 @@ namespace :test do
|
|
24
16
|
task :all => [:build, :test]
|
25
17
|
|
26
18
|
desc 'Build test fixture EPUB file'
|
27
|
-
task :build =>
|
19
|
+
task :build => :clean do
|
28
20
|
input_dir = 'test/fixtures/book'
|
29
21
|
sh "epzip #{input_dir}"
|
30
22
|
small_file = File.read("#{input_dir}/OPS/case-sensitive.xhtml")
|
@@ -57,7 +49,7 @@ end
|
|
57
49
|
Gem::Tasks.new do |tasks|
|
58
50
|
tasks.console.command = 'pry'
|
59
51
|
end
|
60
|
-
task :build =>
|
52
|
+
task :build => :clean
|
61
53
|
|
62
54
|
class ForwardableDefDelegatorsHandler < YARD::Handlers::Ruby::Base
|
63
55
|
handles method_call(:def_delegators)
|
data/docs/Home.markdown
CHANGED
@@ -142,7 +142,8 @@ Then documentation will be available in `doc` directory.
|
|
142
142
|
Requirements
|
143
143
|
------------
|
144
144
|
|
145
|
-
* Ruby 2.
|
145
|
+
* Ruby 2.2.0 or later
|
146
|
+
* `patch` command to install Nokogiri
|
146
147
|
* C compiler to compile Zip/Ruby and Nokogiri
|
147
148
|
|
148
149
|
Note
|
data/epub-parser.gemspec
CHANGED
@@ -14,7 +14,6 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.required_ruby_version = '> 2'
|
15
15
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
|
-
.push('lib/epub/parser/cfi.tab.rb')
|
18
17
|
.push('test/fixtures/book/OPS/ルートファイル.opf')
|
19
18
|
.push('test/fixtures/book/OPS/日本語.xhtml')
|
20
19
|
.push(Dir['docs/*.md'])
|
@@ -46,4 +45,5 @@ Gem::Specification.new do |s|
|
|
46
45
|
s.add_runtime_dependency 'nokogiri', '~> 1.6'
|
47
46
|
s.add_runtime_dependency 'addressable', '>= 2.3.5'
|
48
47
|
s.add_runtime_dependency 'rchardet', '>= 1.6.1'
|
48
|
+
s.add_runtime_dependency 'epub-cfi'
|
49
49
|
end
|
data/lib/epub/parser/version.rb
CHANGED
data/lib/epub/searcher/result.rb
CHANGED
data/test/test_searcher.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require_relative 'helper'
|
3
3
|
require 'epub/searcher'
|
4
|
-
require 'epub/
|
4
|
+
require 'epub/cfi'
|
5
5
|
|
6
6
|
class TestSearcher < Test::Unit::TestCase
|
7
7
|
class TestPublication < self
|
@@ -40,7 +40,7 @@ class TestSearcher < Test::Unit::TestCase
|
|
40
40
|
"epubcfi(/6/2!/4/2/2[idid]/4/4/4/6/2)",
|
41
41
|
"epubcfi(/6/2!/4/2/2[idid]/4/4/4/8/2)"
|
42
42
|
],
|
43
|
-
EPUB::Searcher::Publication.search_element(@package, xpath: './/xhtml:a').collect {|result| result[:location]}.map(&:
|
43
|
+
EPUB::Searcher::Publication.search_element(@package, xpath: './/xhtml:a').collect {|result| result[:location]}.map(&:to_s)
|
44
44
|
)
|
45
45
|
end
|
46
46
|
|
@@ -53,7 +53,7 @@ class TestSearcher < Test::Unit::TestCase
|
|
53
53
|
"epubcfi(/6/2!/4/2/2[idid]/4/4/4/6/2)",
|
54
54
|
"epubcfi(/6/2!/4/2/2[idid]/4/4/4/8/2)"
|
55
55
|
],
|
56
|
-
EPUB::Searcher::Publication.search_element(@package, xpath: './/customnamespace:a', namespaces: {'customnamespace' => 'http://www.w3.org/1999/xhtml'}).collect {|result| result[:location]}.map(&:
|
56
|
+
EPUB::Searcher::Publication.search_element(@package, xpath: './/customnamespace:a', namespaces: {'customnamespace' => 'http://www.w3.org/1999/xhtml'}).collect {|result| result[:location]}.map(&:to_s)
|
57
57
|
)
|
58
58
|
end
|
59
59
|
|
@@ -67,13 +67,13 @@ class TestSearcher < Test::Unit::TestCase
|
|
67
67
|
"epubcfi(/6/2!/4/2/2[idid]/4/4/4/6)",
|
68
68
|
"epubcfi(/6/2!/4/2/2[idid]/4/4/4/8)"
|
69
69
|
],
|
70
|
-
EPUB::Searcher::Publication.search_element(@package, css: 'ol > li').collect {|result| result[:location]}.map(&:
|
70
|
+
EPUB::Searcher::Publication.search_element(@package, css: 'ol > li').collect {|result| result[:location]}.map(&:to_s)
|
71
71
|
)
|
72
72
|
end
|
73
73
|
|
74
74
|
class TesetResult < self
|
75
75
|
def test_to_cfi
|
76
|
-
assert_equal 'epubcfi(/6/2!/4/2/2[idid]/2/4/1,:9,:16)', EPUB::Searcher::Publication.search_text(@package, 'Content').last.to_cfi.
|
76
|
+
assert_equal 'epubcfi(/6/2!/4/2/2[idid]/2/4/1,:9,:16)', EPUB::Searcher::Publication.search_text(@package, 'Content').last.to_cfi.to_s
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
@@ -151,11 +151,11 @@ class TestSearcher < Test::Unit::TestCase
|
|
151
151
|
end
|
152
152
|
|
153
153
|
def test_to_cfi
|
154
|
-
assert_equal 'epubcfi(/4/2/2[idid]/4/4/4/4/2/1,:0,:3)', @result.to_cfi.
|
154
|
+
assert_equal 'epubcfi(/4/2/2[idid]/4/4/4/4/2/1,:0,:3)', @result.to_cfi.to_s
|
155
155
|
end
|
156
156
|
|
157
157
|
def test_to_cfi_img
|
158
|
-
assert_equal 'epubcfi(/4/2/2[idid]/4/4/4/6/2/2)', EPUB::Searcher::XHTML::Restricted.search_text(@doc, '第三節').first.to_cfi.
|
158
|
+
assert_equal 'epubcfi(/4/2/2[idid]/4/4/4/6/2/2)', EPUB::Searcher::XHTML::Restricted.search_text(@doc, '第三節').first.to_cfi.to_s
|
159
159
|
end
|
160
160
|
end
|
161
161
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: epub-parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- KITAITI Makoto
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -290,6 +290,20 @@ dependencies:
|
|
290
290
|
- - ">="
|
291
291
|
- !ruby/object:Gem::Version
|
292
292
|
version: 1.6.1
|
293
|
+
- !ruby/object:Gem::Dependency
|
294
|
+
name: epub-cfi
|
295
|
+
requirement: !ruby/object:Gem::Requirement
|
296
|
+
requirements:
|
297
|
+
- - ">="
|
298
|
+
- !ruby/object:Gem::Version
|
299
|
+
version: '0'
|
300
|
+
type: :runtime
|
301
|
+
prerelease: false
|
302
|
+
version_requirements: !ruby/object:Gem::Requirement
|
303
|
+
requirements:
|
304
|
+
- - ">="
|
305
|
+
- !ruby/object:Gem::Version
|
306
|
+
version: '0'
|
293
307
|
description: Parse EPUB 3 book loosely
|
294
308
|
email:
|
295
309
|
- KitaitiMakoto@gmail.com
|
@@ -302,8 +316,6 @@ files:
|
|
302
316
|
- ".gemtest"
|
303
317
|
- ".gitignore"
|
304
318
|
- ".gitlab-ci.yml"
|
305
|
-
- ".gitmodules"
|
306
|
-
- ".travis.yml"
|
307
319
|
- ".yardopts"
|
308
320
|
- CHANGELOG.markdown
|
309
321
|
- Gemfile
|
@@ -330,7 +342,6 @@ files:
|
|
330
342
|
- lib/epub.rb
|
331
343
|
- lib/epub/book.rb
|
332
344
|
- lib/epub/book/features.rb
|
333
|
-
- lib/epub/cfi.rb
|
334
345
|
- lib/epub/constants.rb
|
335
346
|
- lib/epub/content_document.rb
|
336
347
|
- lib/epub/content_document/navigation.rb
|
@@ -350,9 +361,6 @@ files:
|
|
350
361
|
- lib/epub/ocf/rights.rb
|
351
362
|
- lib/epub/ocf/signatures.rb
|
352
363
|
- lib/epub/parser.rb
|
353
|
-
- lib/epub/parser/cfi.rb
|
354
|
-
- lib/epub/parser/cfi.tab.rb
|
355
|
-
- lib/epub/parser/cfi.y
|
356
364
|
- lib/epub/parser/content_document.rb
|
357
365
|
- lib/epub/parser/metadata.rb
|
358
366
|
- lib/epub/parser/ocf.rb
|
@@ -386,14 +394,12 @@ files:
|
|
386
394
|
- test/fixtures/book/OPS/日本語.xhtml
|
387
395
|
- test/fixtures/book/mimetype
|
388
396
|
- test/helper.rb
|
389
|
-
- test/test_cfi.rb
|
390
397
|
- test/test_content_document.rb
|
391
398
|
- test/test_epub.rb
|
392
399
|
- test/test_fixed_layout.rb
|
393
400
|
- test/test_inspect.rb
|
394
401
|
- test/test_ocf_physical_container.rb
|
395
402
|
- test/test_parser.rb
|
396
|
-
- test/test_parser_cfi.rb
|
397
403
|
- test/test_parser_content_document.rb
|
398
404
|
- test/test_parser_fixed_layout.rb
|
399
405
|
- test/test_parser_ocf.rb
|
@@ -420,20 +426,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
420
426
|
version: '0'
|
421
427
|
requirements: []
|
422
428
|
rubyforge_project:
|
423
|
-
rubygems_version: 2.6.
|
429
|
+
rubygems_version: 2.6.11
|
424
430
|
signing_key:
|
425
431
|
specification_version: 4
|
426
432
|
summary: EPUB 3 Parser
|
427
433
|
test_files:
|
428
434
|
- test/helper.rb
|
429
|
-
- test/test_cfi.rb
|
430
435
|
- test/test_content_document.rb
|
431
436
|
- test/test_epub.rb
|
432
437
|
- test/test_fixed_layout.rb
|
433
438
|
- test/test_inspect.rb
|
434
439
|
- test/test_ocf_physical_container.rb
|
435
440
|
- test/test_parser.rb
|
436
|
-
- test/test_parser_cfi.rb
|
437
441
|
- test/test_parser_content_document.rb
|
438
442
|
- test/test_parser_fixed_layout.rb
|
439
443
|
- test/test_parser_ocf.rb
|
data/.gitmodules
DELETED
data/.travis.yml
DELETED
data/lib/epub/cfi.rb
DELETED
@@ -1,313 +0,0 @@
|
|
1
|
-
module EPUB
|
2
|
-
module CFI
|
3
|
-
SPECIAL_CHARS = '^[](),;=' # "5E", "5B", "5D", "28", "29", "2C", "3B", "3D"
|
4
|
-
RE_ESCAPED_SPECIAL_CHARS = Regexp.escape(SPECIAL_CHARS)
|
5
|
-
|
6
|
-
class << self
|
7
|
-
def escape(string)
|
8
|
-
string.gsub(/([#{RE_ESCAPED_SPECIAL_CHARS}])/o, '^\1')
|
9
|
-
end
|
10
|
-
|
11
|
-
def unescape(string)
|
12
|
-
string.gsub(/\^([#{RE_ESCAPED_SPECIAL_CHARS}])/o, '\1')
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class Location
|
17
|
-
include Comparable
|
18
|
-
|
19
|
-
attr_reader :paths
|
20
|
-
|
21
|
-
def initialize(paths=[])
|
22
|
-
@paths = paths
|
23
|
-
end
|
24
|
-
|
25
|
-
def initialize_copy(original)
|
26
|
-
@paths = original.paths.collect(&:dup)
|
27
|
-
end
|
28
|
-
|
29
|
-
def type
|
30
|
-
@paths.last.type
|
31
|
-
end
|
32
|
-
|
33
|
-
def <=>(other)
|
34
|
-
index = 0
|
35
|
-
other_paths = other.paths
|
36
|
-
cmp = nil
|
37
|
-
paths.each do |path|
|
38
|
-
other_path = other_paths[index]
|
39
|
-
return 1 unless other_path
|
40
|
-
cmp = path <=> other_path
|
41
|
-
break unless cmp == 0
|
42
|
-
index += 1
|
43
|
-
end
|
44
|
-
|
45
|
-
unless cmp == 0
|
46
|
-
if cmp == 1 and paths[index].offset and other_paths[index + 1]
|
47
|
-
return nil
|
48
|
-
else
|
49
|
-
return cmp
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
return nil if paths.last.offset && other_paths[index]
|
54
|
-
|
55
|
-
return -1 if other_paths[index]
|
56
|
-
|
57
|
-
0
|
58
|
-
end
|
59
|
-
|
60
|
-
def to_s
|
61
|
-
paths.join('!')
|
62
|
-
end
|
63
|
-
|
64
|
-
def to_fragment
|
65
|
-
"epubcfi(#{self})"
|
66
|
-
end
|
67
|
-
|
68
|
-
def join(*other_paths)
|
69
|
-
new_paths = paths.dup
|
70
|
-
other_paths.each do |path|
|
71
|
-
new_paths << path
|
72
|
-
end
|
73
|
-
self.class.new(new_paths)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
class Path
|
78
|
-
attr_reader :steps, :offset
|
79
|
-
|
80
|
-
def initialize(steps=[], offset=nil)
|
81
|
-
@steps, @offset = steps, offset
|
82
|
-
end
|
83
|
-
|
84
|
-
def initialize_copy(original)
|
85
|
-
@steps = original.steps.collect(&:dup)
|
86
|
-
@offset = original.offset.dup if original.offset
|
87
|
-
end
|
88
|
-
|
89
|
-
def to_s
|
90
|
-
@string_cache ||= (steps.join + offset.to_s)
|
91
|
-
end
|
92
|
-
|
93
|
-
def to_fragment
|
94
|
-
@fragment_cache ||= "epubcfi(#{self})"
|
95
|
-
end
|
96
|
-
|
97
|
-
def <=>(other)
|
98
|
-
other_steps = other.steps
|
99
|
-
index = 0
|
100
|
-
steps.each do |step|
|
101
|
-
other_step = other_steps[index]
|
102
|
-
return 1 unless other_step
|
103
|
-
cmp = step <=> other_step
|
104
|
-
return cmp unless cmp == 0
|
105
|
-
index += 1
|
106
|
-
end
|
107
|
-
|
108
|
-
return -1 if other_steps[index]
|
109
|
-
|
110
|
-
other_offset = other.offset
|
111
|
-
if offset
|
112
|
-
if other_offset
|
113
|
-
offset <=> other_offset
|
114
|
-
else
|
115
|
-
1
|
116
|
-
end
|
117
|
-
else
|
118
|
-
if other_offset
|
119
|
-
-1
|
120
|
-
else
|
121
|
-
0
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def each_step_with_instruction
|
127
|
-
yield [step, nil]
|
128
|
-
local_path.each_step_with_instruction do |s, instruction|
|
129
|
-
yield [s, instruction]
|
130
|
-
end
|
131
|
-
self
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
class Range < ::Range
|
136
|
-
attr_accessor :parent, :start, :end
|
137
|
-
|
138
|
-
# @todo consider the case subpaths are redirected path
|
139
|
-
# @todo FIXME: too dirty
|
140
|
-
class << self
|
141
|
-
def from_parent_and_start_and_end(parent_path, start_subpath, end_subpath)
|
142
|
-
start_str = start_subpath.join
|
143
|
-
end_str = end_subpath.join
|
144
|
-
|
145
|
-
first_paths = parent_path.collect(&:dup)
|
146
|
-
if start_subpath
|
147
|
-
offset_of_first = start_subpath.last.offset
|
148
|
-
offset_of_first = offset_of_first.dup if offset_of_first
|
149
|
-
last_of_first_paths = first_paths.pop
|
150
|
-
first_paths << last_of_first_paths
|
151
|
-
last_of_first_paths.steps.concat start_subpath.shift.steps
|
152
|
-
first_paths.concat start_subpath
|
153
|
-
first_paths.last.instance_variable_set :@offset, offset_of_first
|
154
|
-
end
|
155
|
-
offset_of_last = end_subpath.last.offset
|
156
|
-
offset_of_last = offset_of_last.dup if offset_of_last
|
157
|
-
last_paths = parent_path.collect(&:dup)
|
158
|
-
last_of_last_paths = last_paths.pop
|
159
|
-
last_paths << last_of_last_paths
|
160
|
-
last_of_last_paths.steps.concat end_subpath.shift.steps
|
161
|
-
last_paths.concat end_subpath
|
162
|
-
last_paths.last.instance_variable_set :@offset, offset_of_last
|
163
|
-
|
164
|
-
first = CFI::Location.new(first_paths)
|
165
|
-
last = CFI::Location.new(last_paths)
|
166
|
-
|
167
|
-
new_range = new(first, last)
|
168
|
-
|
169
|
-
new_range.parent = Location.new(parent_path)
|
170
|
-
new_range.start = start_str
|
171
|
-
new_range.end = end_str
|
172
|
-
|
173
|
-
new_range
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
def to_s
|
178
|
-
@string_cache ||= (first.to_fragment + (exclude_end? ? '...' : '..') + last.to_fragment)
|
179
|
-
end
|
180
|
-
|
181
|
-
def to_fragment
|
182
|
-
@fragment_cache ||= "epubcfi(#{@parent},#{@start},#{@end})"
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
class Step
|
187
|
-
attr_reader :value, :assertion
|
188
|
-
alias step value
|
189
|
-
|
190
|
-
def initialize(value, assertion=nil)
|
191
|
-
@value, @assertion = value, assertion
|
192
|
-
@string_cache = nil
|
193
|
-
end
|
194
|
-
|
195
|
-
def initialize_copy(original)
|
196
|
-
@value = original.value
|
197
|
-
@assertion = original.assertion.dup if original.assertion
|
198
|
-
end
|
199
|
-
|
200
|
-
def to_s
|
201
|
-
@string_cache ||= "/#{value}#{assertion}" # need escape?
|
202
|
-
end
|
203
|
-
|
204
|
-
def <=>(other)
|
205
|
-
value <=> other.value
|
206
|
-
end
|
207
|
-
|
208
|
-
def element?
|
209
|
-
value.even?
|
210
|
-
end
|
211
|
-
|
212
|
-
def character_data?
|
213
|
-
value.odd?
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
class IDAssertion
|
218
|
-
attr_reader :id, :parameters
|
219
|
-
|
220
|
-
def initialize(id, parameters={})
|
221
|
-
@id, @parameters = id, parameters
|
222
|
-
@string_cache = nil
|
223
|
-
end
|
224
|
-
|
225
|
-
def to_s
|
226
|
-
return @string_cache if @string_cache
|
227
|
-
string_cache = '['
|
228
|
-
string_cache << CFI.escape(id) if id
|
229
|
-
parameters.each_pair do |key, values|
|
230
|
-
value = values.join(',')
|
231
|
-
string_cache << ";#{CFI.escape(key)}=#{CFI.escape(value)}"
|
232
|
-
end
|
233
|
-
string_cache << ']'
|
234
|
-
@string_cache = string_cache
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
class TextLocationAssertion
|
239
|
-
attr_reader :preceded, :followed, :parameters
|
240
|
-
|
241
|
-
def initialize(preceded=nil, followed=nil, parameters={})
|
242
|
-
@preceded, @followed, @parameters = preceded, followed, parameters
|
243
|
-
@string_cache = nil
|
244
|
-
end
|
245
|
-
|
246
|
-
def to_s
|
247
|
-
return @string_cache if @string_cache
|
248
|
-
string_cache = '['
|
249
|
-
string_cache << CFI.escape(preceded) if preceded
|
250
|
-
string_cache << ',' << CFI.escape(followed) if followed
|
251
|
-
parameters.each_pair do |key, values|
|
252
|
-
value = values.join(',')
|
253
|
-
string_cache << ";#{CFI.escape(key)}=#{CFI.escape(value)}"
|
254
|
-
end
|
255
|
-
string_cache << ']'
|
256
|
-
@string_cache = string_cache
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
class CharacterOffset
|
261
|
-
attr_reader :value, :assertion
|
262
|
-
alias offset value
|
263
|
-
|
264
|
-
def initialize(value, assertion=nil)
|
265
|
-
@value, @assertion = value, assertion
|
266
|
-
@string_cache = nil
|
267
|
-
end
|
268
|
-
|
269
|
-
def to_s
|
270
|
-
@string_cache ||= ":#{value}#{assertion}" # need escape?
|
271
|
-
end
|
272
|
-
|
273
|
-
def <=>(other)
|
274
|
-
value <=> other.value
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
class TemporalSpatialOffset
|
279
|
-
attr_reader :temporal, :x, :y, :assertion
|
280
|
-
|
281
|
-
def initialize(temporal=nil, x=nil, y=nil, assertion=nil)
|
282
|
-
raise RangeError, "dimension must be in 0..100 but passed #{x}" unless (0.0..100.0).cover?(x) if x
|
283
|
-
raise RangeError, "dimension must be in 0..100 but passed #{y}" unless (0.0..100.0).cover?(y) if y
|
284
|
-
warn "Assertion is passed to #{__class__} but cannot know how to handle with it: #{assertion}" if assertion
|
285
|
-
@temporal, @x, @y, @assertion = temporal, x, y, assertion
|
286
|
-
@string_cache = nil
|
287
|
-
end
|
288
|
-
|
289
|
-
def to_s
|
290
|
-
return @string_cache if @string_cache
|
291
|
-
string_cache = ''
|
292
|
-
string_cache << "~#{temporal}" if temporal
|
293
|
-
string_cache << "@#{x}:#{y}" if x or y
|
294
|
-
@string_cache = string_cache
|
295
|
-
end
|
296
|
-
|
297
|
-
# @note should split the class to spatial offset and temporal-spatial offset?
|
298
|
-
def <=>(other)
|
299
|
-
return -1 if temporal.nil? and other.temporal
|
300
|
-
return 1 if temporal and other.temporal.nil?
|
301
|
-
cmp = temporal <=> other.temporal
|
302
|
-
return cmp unless cmp == 0
|
303
|
-
return -1 if y.nil? and other.y
|
304
|
-
return 1 if y and other.y.nil?
|
305
|
-
cmp = y <=> other.y
|
306
|
-
return cmp unless cmp == 0
|
307
|
-
return -1 if x.nil? and other.x
|
308
|
-
return 1 if x and other.x.nil?
|
309
|
-
cmp = x <=> other.x
|
310
|
-
end
|
311
|
-
end
|
312
|
-
end
|
313
|
-
end
|
data/lib/epub/parser/cfi.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
require 'strscan'
|
2
|
-
require 'epub/parser'
|
3
|
-
require 'epub/parser/cfi.tab'
|
4
|
-
require 'epub/cfi'
|
5
|
-
|
6
|
-
EPUB::Parser::CFI = EPUB::CFIParser
|
7
|
-
|
8
|
-
class EPUB::Parser::CFI
|
9
|
-
include Comparable
|
10
|
-
|
11
|
-
UNICODE_CHARACTER_EXCLUDING_SPECIAL_CHARS_AND_SPACE_AND_DOT_AND_COLON_AND_TILDE_AND_ATMARK_AND_SOLIDUS_AND_EXCLAMATION_MARK_PATTERN = /\u0009|\u000A|\u000D|[\u0022-\u0027]|[\u002A-\u002B]|\u002D|[\u0030-\u0039]|\u003C|[\u003E-\u0040]|[\u0041-\u005A]|\u005C|[\u005F-\u007D]|[\u007F-\uD7FF]|[\uE000-\uFFFD]|[\u10000-\u10FFFF]/ # excluding special chars and space(\u0020) and dot(\u002E) and colon(\u003A) and tilde(\u007E) and atmark(\u0040) and solidus(\u002F) and exclamation mark(\u0021)
|
12
|
-
UNICODE_CHARACTER_PATTERN = Regexp.union(UNICODE_CHARACTER_EXCLUDING_SPECIAL_CHARS_AND_SPACE_AND_DOT_AND_COLON_AND_TILDE_AND_ATMARK_AND_SOLIDUS_AND_EXCLAMATION_MARK_PATTERN, Regexp.new(Regexp.escape(EPUB::CFI::SPECIAL_CHARS), / \.:~@!/))
|
13
|
-
|
14
|
-
class << self
|
15
|
-
def parse(string, debug: false)
|
16
|
-
new(debug: debug).parse(string)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def initialize(debug: false)
|
21
|
-
@yydebug = debug
|
22
|
-
super()
|
23
|
-
end
|
24
|
-
|
25
|
-
def parse(string)
|
26
|
-
if string.start_with? 'epubcfi('
|
27
|
-
string = string['epubcfi('.length .. -2]
|
28
|
-
end
|
29
|
-
@scanner = StringScanner.new(string, true)
|
30
|
-
@q = []
|
31
|
-
until @scanner.eos?
|
32
|
-
case
|
33
|
-
when @scanner.scan(/[1-9]/)
|
34
|
-
@q << [:DIGIT_NON_ZERO, @scanner[0]]
|
35
|
-
when @scanner.scan(/0/)
|
36
|
-
@q << [:ZERO, @scanner[0]]
|
37
|
-
when @scanner.scan(/ /)
|
38
|
-
@q << [:SPACE, @scanner[0]]
|
39
|
-
when @scanner.scan(/\^/)
|
40
|
-
@q << [:CIRCUMFLEX, @scanner[0]]
|
41
|
-
when @scanner.scan(/\[/)
|
42
|
-
@q << [:OPENING_SQUARE_BRACKET, @scanner[0]]
|
43
|
-
when @scanner.scan(/\]/)
|
44
|
-
@q << [:CLOSING_SQUARE_BRACKET, @scanner[0]]
|
45
|
-
when @scanner.scan(/\(/)
|
46
|
-
@q << [:OPENING_PARENTHESIS, @scanner[0]]
|
47
|
-
when @scanner.scan(/\)/)
|
48
|
-
@q << [:CLOSING_PARENTHESIS, @scanner[0]]
|
49
|
-
when @scanner.scan(/,/)
|
50
|
-
@q << [:COMMA, @scanner[0]]
|
51
|
-
when @scanner.scan(/;/)
|
52
|
-
@q << [:SEMICOLON, @scanner[0]]
|
53
|
-
when @scanner.scan(/=/)
|
54
|
-
@q << [:EQUAL, @scanner[0]]
|
55
|
-
when @scanner.scan(/\./)
|
56
|
-
@q << [:DOT, @scanner[0]]
|
57
|
-
when @scanner.scan(/:/)
|
58
|
-
@q << [:COLON, @scanner[0]]
|
59
|
-
when @scanner.scan(/~/)
|
60
|
-
@q << [:TILDE, @scanner[0]]
|
61
|
-
when @scanner.scan(/@/)
|
62
|
-
@q << [:ATMARK, @scanner[0]]
|
63
|
-
when @scanner.scan(/\//)
|
64
|
-
@q << [:SOLIDUS, @scanner[0]]
|
65
|
-
when @scanner.scan(/!/)
|
66
|
-
@q << [:EXCLAMATION_MARK, @scanner[0]]
|
67
|
-
when @scanner.scan(UNICODE_CHARACTER_EXCLUDING_SPECIAL_CHARS_AND_SPACE_AND_DOT_AND_COLON_AND_TILDE_AND_ATMARK_AND_SOLIDUS_AND_EXCLAMATION_MARK_PATTERN)
|
68
|
-
@q << [:UNICODE_CHARACTER_EXCLUDING_SPECIAL_CHARS_AND_SPACE_AND_DOT_AND_COLON_AND_TILDE_AND_ATMARK_AND_SOLIDUS_AND_EXCLAMATION_MARK, @scanner[0]]
|
69
|
-
else
|
70
|
-
raise 'unexpected character'
|
71
|
-
end
|
72
|
-
end
|
73
|
-
@q << [false, false]
|
74
|
-
|
75
|
-
do_parse
|
76
|
-
end
|
77
|
-
|
78
|
-
def next_token
|
79
|
-
@q.shift
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def EPUB::CFI(string)
|
84
|
-
EPUB::Parser::CFI.parse('epubcfi(' + string + ')')
|
85
|
-
end
|
data/lib/epub/parser/cfi.y
DELETED
@@ -1,187 +0,0 @@
|
|
1
|
-
# EPUB::Parser::CFI is prefered but cannot be used.
|
2
|
-
# Racc automatically declare module EPUB::Parser
|
3
|
-
# but EPUB::Parser have been declared as a class.
|
4
|
-
class EPUB::CFIParser
|
5
|
-
rule
|
6
|
-
|
7
|
-
fragment : path range_zero_or_one
|
8
|
-
{
|
9
|
-
if val[1]
|
10
|
-
result = CFI::Range.from_parent_and_start_and_end(val[0], *val[1])
|
11
|
-
else
|
12
|
-
result = CFI::Location.new(val[0])
|
13
|
-
end
|
14
|
-
}
|
15
|
-
|
16
|
-
range_zero_or_one : range
|
17
|
-
|
|
18
|
-
|
19
|
-
path : step local_path
|
20
|
-
{
|
21
|
-
path, redirected_path = *val[1]
|
22
|
-
path.steps.unshift val[0]
|
23
|
-
result = val[1]
|
24
|
-
}
|
25
|
-
|
26
|
-
range : COMMA local_path COMMA local_path
|
27
|
-
{result = [val[1], val[3]]}
|
28
|
-
|
29
|
-
local_path : step_zero_or_more redirected_path
|
30
|
-
{result = [CFI::Path.new(val[0])] + val[1]}
|
31
|
-
| step_zero_or_more offset_zero_or_one
|
32
|
-
{result = [CFI::Path.new(val[0], val[1])]}
|
33
|
-
|
34
|
-
step_zero_or_more : step_zero_or_more step
|
35
|
-
{result = val[0] + [val[1]]}
|
36
|
-
| step
|
37
|
-
{result = [val[0]]}
|
38
|
-
|
|
39
|
-
{result = []}
|
40
|
-
|
41
|
-
redirected_path : EXCLAMATION_MARK offset
|
42
|
-
{result = [CFI::Path.new([], val[1])]}
|
43
|
-
| EXCLAMATION_MARK path
|
44
|
-
{result = val[1]}
|
45
|
-
|
46
|
-
step : SOLIDUS integer assertion_part_zero_or_one
|
47
|
-
{
|
48
|
-
assertion = val[2] ? CFI::IDAssertion.new(val[2][0], val[2][2]) : nil
|
49
|
-
result = CFI::Step.new(val[1].to_i, assertion)
|
50
|
-
}
|
51
|
-
|
52
|
-
offset_zero_or_one : offset
|
53
|
-
|
|
54
|
-
|
55
|
-
offset : COLON integer assertion_part_zero_or_one
|
56
|
-
{
|
57
|
-
assertion = val[2] ? CFI::TextLocationAssertion.new(*val[2]) : nil
|
58
|
-
result = CFI::CharacterOffset.new(val[1].to_i, assertion)
|
59
|
-
}
|
60
|
-
| spatial_offset assertion_part_zero_or_one
|
61
|
-
{result = CFI::TemporalSpatialOffset.new(nil, val[0][0].to_f, val[0][1].to_f, val[2])}
|
62
|
-
| TILDE number spatial_offset_zero_or_one assertion_part_zero_or_one
|
63
|
-
{
|
64
|
-
x = val[2] ? val[2][0].to_f : nil
|
65
|
-
y = val[2] ? val[2][1].to_f : nil
|
66
|
-
result = CFI::TemporalSpatialOffset.new(val[1].to_f, x, y, val[3])
|
67
|
-
}
|
68
|
-
|
69
|
-
spatial_offset_zero_or_one : spatial_offset
|
70
|
-
|
|
71
|
-
|
72
|
-
spatial_offset : ATMARK number COLON number
|
73
|
-
{result = [val[1], val[3]]}
|
74
|
-
|
75
|
-
assertion_part_zero_or_one : opening_square_bracket assertion closing_square_bracket
|
76
|
-
{result = val[1]}
|
77
|
-
|
|
78
|
-
|
79
|
-
number : DIGIT_NON_ZERO digit_zero_or_more fractional_portion_zero_or_one
|
80
|
-
{result = val.join}
|
81
|
-
| ZERO fractional_portion_zero_or_one
|
82
|
-
{result = val.join}
|
83
|
-
|
84
|
-
fractional_portion_zero_or_one : fractional_portion
|
85
|
-
|
|
86
|
-
|
87
|
-
fractional_portion : DOT digit_zero_or_more DIGIT_NON_ZERO
|
88
|
-
{result = val.join}
|
89
|
-
| DOT DIGIT_NON_ZERO
|
90
|
-
{result = val.join}
|
91
|
-
|
92
|
-
integer : ZERO
|
93
|
-
| DIGIT_NON_ZERO digit_zero_or_more
|
94
|
-
{result = val.join}
|
95
|
-
|
96
|
-
digit_zero_or_more : digit_zero_or_more digit
|
97
|
-
{result = val.join}
|
98
|
-
| digit
|
99
|
-
|
|
100
|
-
|
101
|
-
assertion : value_csv_one_or_two parameter_zero_or_more
|
102
|
-
{result = [val[0][0], val[0][1], val[1]]} # Cannot see id assertion or text location assertion when val[0]'s length is 1. It can be done by context.
|
103
|
-
| COMMA value parameter_zero_or_more
|
104
|
-
{result = [nil, val[1], val[2]]}
|
105
|
-
| parameter parameter_zero_or_more
|
106
|
-
{result = [nil, nil, val[0].merge(val[1])]} # Cannot see id assertion or text location assertion when val[0]'s length is 1. It can be done by context. In EPUBCFI 3.0.1 spec, only side-bias parameter is defined and we can say it's text location assertion of the assertion has parameters. But when the spec is extended and other parameter definitions added, we might become not able to say so.
|
107
|
-
|
108
|
-
value_csv_one_or_two : value COMMA value
|
109
|
-
{result = [val[0], val[2]]}
|
110
|
-
| value
|
111
|
-
{result = [val[0]]}
|
112
|
-
|
113
|
-
parameter_zero_or_more : parameter_zero_or_more parameter
|
114
|
-
{result = val[0].merge(val[1])}
|
115
|
-
| parameter
|
116
|
-
{result = val[0]}
|
117
|
-
|
|
118
|
-
{result = {}}
|
119
|
-
|
120
|
-
parameter : SEMICOLON value_no_space EQUAL csv
|
121
|
-
{result = {val[1] => val[3]}}
|
122
|
-
|
123
|
-
csv : csv COMMA value
|
124
|
-
{result = val[0] + [val[2]]}
|
125
|
-
| value
|
126
|
-
{result = [val[0]]}
|
127
|
-
|
128
|
-
value : string_escaped_special_chars
|
129
|
-
{result = val[0]}
|
130
|
-
|
131
|
-
value_no_space: string_escaped_special_chars_excluding_space
|
132
|
-
|
133
|
-
escaped_special_chars : CIRCUMFLEX CIRCUMFLEX
|
134
|
-
{result = val[1]}
|
135
|
-
| CIRCUMFLEX square_brackets
|
136
|
-
{result = val[1]}
|
137
|
-
| CIRCUMFLEX parentheses
|
138
|
-
{result = val[1]}
|
139
|
-
| CIRCUMFLEX COMMA
|
140
|
-
{result = val[1]}
|
141
|
-
| CIRCUMFLEX SEMICOLON
|
142
|
-
{result = val[1]}
|
143
|
-
| CIRCUMFLEX EQUAL
|
144
|
-
{result = val[1]}
|
145
|
-
|
146
|
-
character_escaped_special : character_excluding_special_chars
|
147
|
-
| escaped_special_chars
|
148
|
-
|
149
|
-
string_escaped_special_chars : string_escaped_special_chars character_escaped_special
|
150
|
-
{result = val.join}
|
151
|
-
| character_escaped_special
|
152
|
-
{result = val[0]}
|
153
|
-
|
154
|
-
string_escaped_special_chars_excluding_space : string_escaped_special_chars_excluding_space character_escaped_special_excluding_space
|
155
|
-
| character_escaped_special_excluding_space
|
156
|
-
|
157
|
-
character_escaped_special_excluding_space : character_excluding_special_chars_and_space
|
158
|
-
| escaped_special_chars
|
159
|
-
|
160
|
-
digit : ZERO
|
161
|
-
| DIGIT_NON_ZERO
|
162
|
-
|
163
|
-
square_brackets : opening_square_bracket
|
164
|
-
| closing_square_bracket
|
165
|
-
|
166
|
-
opening_square_bracket : OPENING_SQUARE_BRACKET
|
167
|
-
|
168
|
-
closing_square_bracket : CLOSING_SQUARE_BRACKET
|
169
|
-
|
170
|
-
parentheses : OPENING_PARENTHESIS
|
171
|
-
| CLOSING_PARENTHESIS
|
172
|
-
|
173
|
-
character_excluding_special_chars : character_excluding_special_chars_and_space
|
174
|
-
| SPACE
|
175
|
-
|
176
|
-
character_excluding_special_chars_and_space : character_excluding_special_chars_and_space_and_dot_and_colon_and_tilde_and_atmark_and_solidus_and_exclamation_mark
|
177
|
-
| DOT
|
178
|
-
| COLON
|
179
|
-
| TILDE
|
180
|
-
| ATMARK
|
181
|
-
| SOLIDUS
|
182
|
-
| EXCLAMATION_MARK
|
183
|
-
|
184
|
-
character_excluding_special_chars_and_space_and_dot_and_colon_and_tilde_and_atmark_and_solidus_and_exclamation_mark : UNICODE_CHARACTER_EXCLUDING_SPECIAL_CHARS_AND_SPACE_AND_DOT_AND_COLON_AND_TILDE_AND_ATMARK_AND_SOLIDUS_AND_EXCLAMATION_MARK
|
185
|
-
| digit
|
186
|
-
|
187
|
-
end
|
data/test/test_cfi.rb
DELETED
@@ -1,227 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
require_relative 'helper'
|
3
|
-
require 'epub/cfi'
|
4
|
-
require 'epub/parser/cfi'
|
5
|
-
require 'nokogiri/diff'
|
6
|
-
|
7
|
-
class TestCFI < Test::Unit::TestCase
|
8
|
-
def test_escape
|
9
|
-
assert_equal '^^^[^]^(^)^,^;^=', EPUB::CFI.escape('^[](),;=')
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_unescape
|
13
|
-
assert_equal '^[](),;=', EPUB::CFI.unescape('^^^[^]^(^)^,^;^=')
|
14
|
-
end
|
15
|
-
|
16
|
-
class TestPath < self
|
17
|
-
data([
|
18
|
-
'/6/14[chap05ref]!/4[body01]/10/2/1:3[2^[1^]]',
|
19
|
-
'/6/4!/4/10/2/1:3[Ф-"spa ce"-99%-aa^[bb^]^^]',
|
20
|
-
'/6/4!/4/10/2/1:3[Ф-"spa%20ce"-99%25-aa^[bb^]^^]',
|
21
|
-
'/6/4!/4/10/2/1:3[%d0%a4-"spa%20ce"-99%25-aa^[bb^]^^]',
|
22
|
-
'/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[yyy]',
|
23
|
-
'/6/4[chap01ref]!/4[body01]/10[para05]/1:3[xx,y]',
|
24
|
-
'/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[,y]',
|
25
|
-
'/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[;s=b]',
|
26
|
-
'/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[yyy;s=b]',
|
27
|
-
'/6/4[chap01ref]!/4[body01]/10[para05]/2[;s=b]',
|
28
|
-
'/6/4[chap01ref]!/4[body01]/10[para05]/3:10',
|
29
|
-
'/6/4[chap01ref]!/4[body01]/16[svgimg]',
|
30
|
-
'/6/4[chap01ref]!/4[body01]/10[para05]/1:0',
|
31
|
-
'/6/4[chap01ref]!/4[body01]/10[para05]/2/1:0',
|
32
|
-
'/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3',
|
33
|
-
].reduce({}) {|data, cfi|
|
34
|
-
data[cfi] = cfi
|
35
|
-
data
|
36
|
-
})
|
37
|
-
def test_to_s(cfi)
|
38
|
-
assert_equal cfi, epubcfi(cfi).to_s
|
39
|
-
end
|
40
|
-
|
41
|
-
data([
|
42
|
-
'epubcfi(/6/14[chap05ref]!/4[body01]/10/2/1:3[2^[1^]])',
|
43
|
-
'epubcfi(/6/4!/4/10/2/1:3[Ф-"spa ce"-99%-aa^[bb^]^^])',
|
44
|
-
'epubcfi(/6/4!/4/10/2/1:3[Ф-"spa%20ce"-99%25-aa^[bb^]^^])',
|
45
|
-
'epubcfi(/6/4!/4/10/2/1:3[%d0%a4-"spa%20ce"-99%25-aa^[bb^]^^])',
|
46
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[yyy])',
|
47
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/1:3[xx,y])',
|
48
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[,y])',
|
49
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[;s=b])',
|
50
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[yyy;s=b])',
|
51
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2[;s=b])',
|
52
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/3:10)',
|
53
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/16[svgimg])',
|
54
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/1:0)',
|
55
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:0)',
|
56
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)',
|
57
|
-
].reduce({}) {|data, cfi|
|
58
|
-
data[cfi] = cfi
|
59
|
-
data
|
60
|
-
})
|
61
|
-
def test_to_fragment(cfi)
|
62
|
-
assert_equal cfi, EPUB::Parser::CFI.parse(cfi).to_fragment
|
63
|
-
end
|
64
|
-
|
65
|
-
def test_compare
|
66
|
-
assert_equal -1, epubcfi('/6/4[id]') <=> epubcfi('/6/5')
|
67
|
-
assert_equal 0, epubcfi('/6/4') <=> epubcfi('/6/4')
|
68
|
-
assert_equal 1, epubcfi('/6/4') <=> epubcfi('/4/6')
|
69
|
-
assert_equal 1, epubcfi('/6/4!/4@3:7') <=> epubcfi('/6/4!/4')
|
70
|
-
assert_equal 1,
|
71
|
-
epubcfi('/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[yyy]') <=>
|
72
|
-
epubcfi('/6/4[chap01ref]!/4[body01]/10[para05]/1:3[xx,y]')
|
73
|
-
assert_nil epubcfi('/6/4[chap01ref]!/4[body01]/10[para05]/3:10') <=>
|
74
|
-
epubcfi('/6/4[chap01ref]!/4[body01]/10[para05]/3!:10')
|
75
|
-
assert_equal 1, epubcfi('/6/4') <=> epubcfi('/6')
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
class TestRange < self
|
80
|
-
def test_attributes
|
81
|
-
parent = epubcfi('/6/4[chap01ref]!/4[body01]/10[para05]')
|
82
|
-
first = epubcfi('/6/4[chap01ref]!/4[body01]/10[para05]/2/1:1')
|
83
|
-
last = epubcfi('/6/4[chap01ref]!/4[body01]/10[para05]/3:4')
|
84
|
-
range = epubcfi('/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4')
|
85
|
-
assert_equal 0, first <=> range.first
|
86
|
-
assert_equal 0, last <=> range.last
|
87
|
-
|
88
|
-
assert_equal 0, parent <=> range.parent
|
89
|
-
end
|
90
|
-
|
91
|
-
def test_to_s
|
92
|
-
assert_equal 'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:1)..epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/3:4)', epubcfi('/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4').to_s
|
93
|
-
assert_equal 'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]!/2/1:1)..epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]!/3:4)', epubcfi('/6/4[chap01ref]!/4[body01]/10[para05],!/2/1:1,!/3:4').to_s
|
94
|
-
end
|
95
|
-
|
96
|
-
def test_to_fragment
|
97
|
-
cfi = '/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4'
|
98
|
-
assert_equal 'epubcfi(' + cfi + ')', epubcfi('/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4').to_fragment
|
99
|
-
end
|
100
|
-
|
101
|
-
def test_cover
|
102
|
-
assert_true epubcfi('/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4').cover? epubcfi('/6/4[chap01ref]!/4[body01]/10[para05]/2/2/4')
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
class TestStep < self
|
107
|
-
def test_to_s
|
108
|
-
assert_equal '/6', EPUB::CFI::Step.new(6).to_s
|
109
|
-
assert_equal '/4[id]', EPUB::CFI::Step.new(4, EPUB::CFI::IDAssertion.new('id')).to_s
|
110
|
-
end
|
111
|
-
|
112
|
-
def test_compare
|
113
|
-
assert_equal 0, EPUB::CFI::Step.new(6) <=> EPUB::CFI::Step.new(6, 'assertion')
|
114
|
-
assert_equal -1, EPUB::CFI::Step.new(6) <=> EPUB::CFI::Step.new(7)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
class TestIDAssertion < self
|
119
|
-
def test_to_s
|
120
|
-
assert_equal '[id]', EPUB::CFI::IDAssertion.new('id').to_s
|
121
|
-
assert_equal '[id;p=a]', EPUB::CFI::IDAssertion.new('id', {'p' => ['a']}).to_s
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
class TestTextLocationAssertion < self
|
126
|
-
def test_to_s
|
127
|
-
assert_equal '[yyy]', EPUB::CFI::TextLocationAssertion.new('yyy').to_s
|
128
|
-
assert_equal '[xx,y]', EPUB::CFI::TextLocationAssertion.new('xx', 'y').to_s
|
129
|
-
assert_equal '[,y]', EPUB::CFI::TextLocationAssertion.new(nil, 'y').to_s
|
130
|
-
assert_equal '[;s=b]', EPUB::CFI::TextLocationAssertion.new(nil, nil, {'s' => ['b']}).to_s
|
131
|
-
assert_equal '[yyy;s=b]', EPUB::CFI::TextLocationAssertion.new('yyy', nil, {'s' => ['b']}).to_s
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
class TestCharacterOffset < self
|
136
|
-
def test_to_s
|
137
|
-
assert_equal ':1', EPUB::CFI::CharacterOffset.new(1).to_s
|
138
|
-
assert_equal ':2[yyy]', EPUB::CFI::CharacterOffset.new(2, EPUB::CFI::TextLocationAssertion.new('yyy')).to_s
|
139
|
-
end
|
140
|
-
|
141
|
-
def test_compare
|
142
|
-
assert_equal 0,
|
143
|
-
EPUB::CFI::CharacterOffset.new(3) <=>
|
144
|
-
EPUB::CFI::CharacterOffset.new(3, EPUB::CFI::TextLocationAssertion.new('yyy'))
|
145
|
-
assert_equal -1,
|
146
|
-
EPUB::CFI::CharacterOffset.new(4) <=>
|
147
|
-
EPUB::CFI::CharacterOffset.new(5)
|
148
|
-
assert_equal 1,
|
149
|
-
EPUB::CFI::CharacterOffset.new(4, EPUB::CFI::TextLocationAssertion.new(nil, 'xx')) <=>
|
150
|
-
EPUB::CFI::CharacterOffset.new(2)
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
class TestSpatialOffset < self
|
155
|
-
def test_to_s
|
156
|
-
assert_equal '@0.5:30.2', EPUB::CFI::TemporalSpatialOffset.new(nil, 0.5, 30.2).to_s
|
157
|
-
assert_equal '@0:100', EPUB::CFI::TemporalSpatialOffset.new(nil, 0, 100).to_s
|
158
|
-
assert_equal '@50:50.0', EPUB::CFI::TemporalSpatialOffset.new(nil, 50, 50.0).to_s
|
159
|
-
end
|
160
|
-
|
161
|
-
def test_compare
|
162
|
-
assert_equal 0,
|
163
|
-
EPUB::CFI::TemporalSpatialOffset.new(nil, 30, 40) <=>
|
164
|
-
EPUB::CFI::TemporalSpatialOffset.new(nil, 30, 40)
|
165
|
-
assert_equal 1,
|
166
|
-
EPUB::CFI::TemporalSpatialOffset.new(nil, 30, 40) <=>
|
167
|
-
EPUB::CFI::TemporalSpatialOffset.new(nil, 40, 30)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
class TestTemporalOffset < self
|
172
|
-
def test_to_s
|
173
|
-
assert_equal '~23.5', EPUB::CFI::TemporalSpatialOffset.new(23.5).to_s
|
174
|
-
end
|
175
|
-
|
176
|
-
def test_compare
|
177
|
-
assert_equal 0,
|
178
|
-
EPUB::CFI::TemporalSpatialOffset.new(23.5) <=>
|
179
|
-
EPUB::CFI::TemporalSpatialOffset.new(23.5)
|
180
|
-
assert_equal -1,
|
181
|
-
EPUB::CFI::TemporalSpatialOffset.new(23) <=>
|
182
|
-
EPUB::CFI::TemporalSpatialOffset.new(23.5)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
class TestTemporalSpatialOffset < self
|
187
|
-
def test_to_s
|
188
|
-
assert_equal '~23.5@50:30.0', EPUB::CFI::TemporalSpatialOffset.new(23.5, 50, 30.0).to_s
|
189
|
-
end
|
190
|
-
|
191
|
-
def test_compare
|
192
|
-
assert_equal 0,
|
193
|
-
EPUB::CFI::TemporalSpatialOffset.new(23.5, 30, 40) <=>
|
194
|
-
EPUB::CFI::TemporalSpatialOffset.new(23.5, 30, 40.0)
|
195
|
-
assert_equal 1,
|
196
|
-
EPUB::CFI::TemporalSpatialOffset.new(23.5, 30, 40) <=>
|
197
|
-
EPUB::CFI::TemporalSpatialOffset.new(23.5)
|
198
|
-
assert_equal -1,
|
199
|
-
EPUB::CFI::TemporalSpatialOffset.new(nil, 30, 40) <=>
|
200
|
-
EPUB::CFI::TemporalSpatialOffset.new(23.5, 30, 40)
|
201
|
-
assert_equal -1,
|
202
|
-
EPUB::CFI::TemporalSpatialOffset.new(23.5, 30, 40) <=>
|
203
|
-
EPUB::CFI::TemporalSpatialOffset.new(23.5, 30, 50)
|
204
|
-
assert_equal 1,
|
205
|
-
EPUB::CFI::TemporalSpatialOffset.new(24, 30, 40) <=>
|
206
|
-
EPUB::CFI::TemporalSpatialOffset.new(23.5, 100, 100)
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
private
|
211
|
-
|
212
|
-
def epubcfi(string)
|
213
|
-
EPUB::Parser::CFI.new.parse(string)
|
214
|
-
end
|
215
|
-
|
216
|
-
def assert_equal_node(expected, actual, message='')
|
217
|
-
diff = AssertionMessage.delayed_diff(expected.to_s, actual.to_s)
|
218
|
-
message = build_message(message, <<EOT, expected, actual, diff)
|
219
|
-
<?>
|
220
|
-
expected but was
|
221
|
-
<?>.?
|
222
|
-
EOT
|
223
|
-
assert_block message do
|
224
|
-
expected.tdiff_equal actual
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
data/test/test_parser_cfi.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
require_relative 'helper'
|
3
|
-
require 'epub/parser/cfi'
|
4
|
-
|
5
|
-
class TestParserCFI < Test::Unit::TestCase
|
6
|
-
def setup
|
7
|
-
@parser = EPUB::Parser::CFI.new(debug: true)
|
8
|
-
end
|
9
|
-
|
10
|
-
# from http://www.idpf.org/epub/linking/cfi/epub-cfi.html
|
11
|
-
data([
|
12
|
-
'epubcfi(/6/14[chap05ref]!/4[body01]/10/2/1:3[2^[1^]])',
|
13
|
-
'epubcfi(/6/4!/4/10/2/1:3[Ф-"spa ce"-99%-aa^[bb^]^^])',
|
14
|
-
'epubcfi(/6/4!/4/10/2/1:3[Ф-"spa%20ce"-99%25-aa^[bb^]^^])',
|
15
|
-
'epubcfi(/6/4!/4/10/2/1:3[%d0%a4-"spa%20ce"-99%25-aa^[bb^]^^])',
|
16
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[yyy])',
|
17
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/1:3[xx,y])',
|
18
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[,y])',
|
19
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[;s=b])',
|
20
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[yyy;s=b])',
|
21
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[^(;s=b])',
|
22
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2[;s=b])',
|
23
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/3:10)',
|
24
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/16[svgimg])',
|
25
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/1:0)',
|
26
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:0)',
|
27
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)',
|
28
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)',
|
29
|
-
'epubcfi(/6,:1,:3)',
|
30
|
-
'epubcfi(/6/4[chap01ref]!/4[body01]/10[mov01]~23.5@5.75:97.6)'
|
31
|
-
].reduce({}) {|data, cfi|
|
32
|
-
data[cfi] = cfi
|
33
|
-
data
|
34
|
-
})
|
35
|
-
def test_raise_no_error_on_parsing_valid_cfi(cfi)
|
36
|
-
assert_nothing_raised do
|
37
|
-
@parser.parse(cfi)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
data([
|
42
|
-
'/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[(;s=b]',
|
43
|
-
'/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3[);s=b]'
|
44
|
-
].reduce({}) {|data, cfi|
|
45
|
-
data[cfi] = cfi
|
46
|
-
data
|
47
|
-
})
|
48
|
-
def test_raise_error_on_parsing_invalid_cfi(cfi)
|
49
|
-
assert_raise Racc::ParseError do
|
50
|
-
EPUB::CFI(cfi)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|