epub-parser 0.1.4 → 0.1.5

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.markdown +10 -0
  4. data/README.markdown +43 -27
  5. data/bin/epubinfo +22 -0
  6. data/docs/EpubOpen.markdown +43 -0
  7. data/docs/Epubinfo.markdown +37 -0
  8. data/docs/FixedLayout.markdown +3 -5
  9. data/docs/Home.markdown +30 -15
  10. data/docs/Item.markdown +14 -14
  11. data/epub-parser.gemspec +5 -2
  12. data/lib/epub.rb +14 -1
  13. data/lib/epub/content_document.rb +1 -5
  14. data/lib/epub/content_document/navigation.rb +3 -5
  15. data/lib/epub/content_document/xhtml.rb +25 -1
  16. data/lib/epub/inspector.rb +43 -0
  17. data/lib/epub/ocf/container.rb +2 -0
  18. data/lib/epub/parser.rb +0 -2
  19. data/lib/epub/parser/content_document.rb +3 -5
  20. data/lib/epub/parser/ocf.rb +2 -4
  21. data/lib/epub/parser/publication.rb +7 -7
  22. data/lib/epub/parser/version.rb +1 -1
  23. data/lib/epub/publication.rb +1 -0
  24. data/lib/epub/publication/package.rb +20 -1
  25. data/lib/epub/publication/package/bindings.rb +5 -1
  26. data/lib/epub/publication/package/guide.rb +1 -0
  27. data/lib/epub/publication/package/manifest.rb +40 -5
  28. data/lib/epub/publication/package/metadata.rb +7 -10
  29. data/lib/epub/publication/package/spine.rb +14 -4
  30. data/lib/method_decorators/deprecated.rb +84 -0
  31. data/test/fixtures/book/OPS/nav.xhtml +2 -0
  32. data/test/helper.rb +4 -2
  33. data/test/test_content_document.rb +21 -0
  34. data/test/test_epub.rb +12 -0
  35. data/test/test_fixed_layout.rb +0 -1
  36. data/test/test_inspect.rb +121 -0
  37. data/test/test_parser_content_document.rb +3 -0
  38. data/test/test_parser_fixed_layout.rb +1 -1
  39. data/test/test_parser_ocf.rb +1 -1
  40. data/test/test_publication.rb +125 -4
  41. metadata +56 -8
@@ -2,6 +2,10 @@ module EPUB
2
2
  module Publication
3
3
  class Package
4
4
  class Metadata
5
+ include Inspector::PublicationModel
6
+ include MethodDecorators
7
+ extend MethodDecorators
8
+
5
9
  DC_ELEMS = [:identifiers, :titles, :languages] +
6
10
  [:contributors, :coverages, :creators, :dates, :descriptions, :formats, :publishers,
7
11
  :relations, :rights, :sources, :subjects, :types]
@@ -51,8 +55,8 @@ module EPUB
51
55
  end
52
56
  end
53
57
 
58
+ +Deprecated.new {|klass, method| "#{klass}##{method} is deprecated. Use #to_h instead."}
54
59
  def to_hash
55
- warn "#{self.class}##{__method__} is obsolete"
56
60
  to_h
57
61
  end
58
62
 
@@ -83,15 +87,8 @@ module EPUB
83
87
 
84
88
  attr_accessor :content, :id, :lang, :dir
85
89
 
86
- def inspect
87
- ivs = instance_variables.map {|iv|
88
- [iv, instance_variable_get(iv).inspect].join('=')
89
- }.join(' ')
90
- '<#%s:%#0x %s>' % [self.class, __id__, ivs]
91
- end
92
-
93
90
  def to_s
94
- content
91
+ content.to_s
95
92
  end
96
93
  end
97
94
 
@@ -133,7 +130,7 @@ module EPUB
133
130
  end
134
131
 
135
132
  def to_s
136
- content
133
+ content.to_s
137
134
  end
138
135
  end
139
136
 
@@ -2,13 +2,17 @@ module EPUB
2
2
  module Publication
3
3
  class Package
4
4
  class Spine
5
+ include Inspector::PublicationModel
5
6
  attr_accessor :package,
6
7
  :id, :toc, :page_progression_direction
7
8
  attr_reader :itemrefs
8
9
 
10
+ def initialize
11
+ @itemrefs = []
12
+ end
13
+
9
14
  # @return self
10
15
  def <<(itemref)
11
- @itemrefs ||= []
12
16
  itemref.spine = self
13
17
  @itemrefs << itemref
14
18
  self
@@ -39,12 +43,16 @@ module EPUB
39
43
 
40
44
  attr_accessor :spine,
41
45
  :idref, :linear, :id, :properties
42
- alias linear? linear
43
46
 
44
47
  def initialize
45
48
  @properties = []
46
49
  end
47
50
 
51
+ # @return [true|false]
52
+ def linear?
53
+ !! linear
54
+ end
55
+
48
56
  # @return [Package::Manifest::Item] item referred by this object
49
57
  def item
50
58
  @item ||= @spine.package.manifest[idref]
@@ -56,9 +64,11 @@ module EPUB
56
64
  end
57
65
 
58
66
  def ==(other)
59
- [:spine, :idref, :linear, :id].all? {|meth|
67
+ [:spine, :idref, :id].all? {|meth|
60
68
  self.__send__(meth) == other.__send__(meth)
61
- } and (other.properties - properties).empty?
69
+ } and
70
+ (linear? == other.linear?) and
71
+ (other.properties - properties).empty?
62
72
  end
63
73
 
64
74
  # @return ["left", "right", nil]
@@ -0,0 +1,84 @@
1
+ require 'method_decorators'
2
+
3
+ module MethodDecorators
4
+ # Example:
5
+ # class MyClass
6
+ # extend MethodDecorators
7
+ #
8
+ # +MethodDecorators::Deprecated
9
+ # def deprecated_method
10
+ # brand_new_method
11
+ # end
12
+ # end
13
+ # When deprecated_method is called, message
14
+ # "MyClass#deprecated_method is deprecated"
15
+ # is output.
16
+ #
17
+ # Another example:
18
+ # class MyClass
19
+ # extend MethodDecorators
20
+ #
21
+ # +MethodDecorators::Deprecated.new('deprecated_method will be removed in the future')
22
+ # def deprecated_method
23
+ # brand_new_method
24
+ # end
25
+ # end
26
+ # Above output given message
27
+ # "deprecated_method will be removed in the future"
28
+ #
29
+ # Custom message example:
30
+ # class MyClass
31
+ # extend MethodDecorators
32
+ #
33
+ # +MethodDecorators::Deprecated.new {|class_name, method_name| "#{class_name}##{method_name} will be removed in the future. Use #{class_name}#brand_new_method instead"}
34
+ # def deprecated_method
35
+ # brand_new_method
36
+ # end
37
+ # end
38
+ # Outputs
39
+ # "MyClass#deprecated_method will be removed in the future. Use MyClass#brand_new_method instead"
40
+ # As you see, you can use class name as the first argument and method name as the second in the block.
41
+ #
42
+ # Formatter example:
43
+ # class Formatter2
44
+ # def call(class_name, method_name)
45
+ # "#{class_name}##{method_name} will be removed after the next version. Use #{class_name}#brand_new_method instead"
46
+ # end
47
+ # end
48
+ # class MyClass
49
+ # extend MethodDecorators
50
+ #
51
+ # formatter1 = ->(class_mane, method_name) {"#{class_name}##{method_name} will be removed in the next version. Use #{class_name}#brand_new_method instead"}
52
+ # +MethodDecorators::Deprecated.new(formatter1)
53
+ # def very_old_method
54
+ # brand_new_method
55
+ # end
56
+ #
57
+ # + MethodDecorators::Deprecated.new(Formatter2.new)
58
+ # def deprecated_method
59
+ # brand_new_method
60
+ # end
61
+ # end
62
+ # Outputs
63
+ # "MyClass#deprecated_method will be removed in the future. Use MyClass#brand_new_method instead"
64
+ # You can give any object which responds to method "call" like Proc.
65
+ class Deprecated < Decorator
66
+ DEFAULT_FORMATTER = lambda {|class_name, method_name| "#{class_name}##{method_name} is deprecated"}
67
+ def initialize(message=nil, &blk)
68
+ @message = message || blk || DEFAULT_FORMATTER
69
+ end
70
+
71
+ def call(orig, this, *args, &blk)
72
+ warn message(this.class, orig.name)
73
+ orig.call(*args, &blk)
74
+ end
75
+
76
+ def message(class_name, method_name)
77
+ if @message.respond_to? :call
78
+ @message.call(class_name, method_name)
79
+ else
80
+ @message.to_s
81
+ end
82
+ end
83
+ end
84
+ end
@@ -17,6 +17,8 @@
17
17
  <ol>
18
18
  <li><a href="item-2.xhtml#section1">第一節</a></li>
19
19
  <li><a href="item-2.xhtml#section2">第二節</a></li>
20
+ <li><a href="item-2.xhtml#section3"><img src="image/nav-2-3.png" alt="第三節"/></a></li>
21
+ <li><a href="item-2.xhtml#section4"><iframe src="external/document.html" name="第四節"></iframe></a></li>
20
22
  </ol>
21
23
  </li>
22
24
  </ol>
data/test/helper.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  require 'simplecov'
2
2
  SimpleCov.start do
3
- add_filter '/test|deps/'
3
+ add_filter '/test|deps|method_decorators/'
4
4
  end
5
5
 
6
- require 'test/unit/full'
6
+ require 'test/unit'
7
+ require 'test/unit/rr'
8
+ require 'test/unit/notify'
7
9
  require 'epub/parser'
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
  require_relative 'helper'
2
3
 
3
4
  class TestContentDocument < Test::Unit::TestCase
@@ -29,4 +30,24 @@ class TestContentDocument < Test::Unit::TestCase
29
30
  doc.item = item2
30
31
  assert_false doc.top_level?
31
32
  end
33
+
34
+ def test_read_returns_content_document_as_string
35
+ item = stub
36
+ stub(item).read {'content'}
37
+ content_doc = XHTML.new
38
+ content_doc.item = item
39
+ assert_equal 'content', content_doc.read
40
+ end
41
+
42
+ def test_title_returns_value_of_title_element
43
+ content_doc = XHTML.new
44
+ stub(content_doc).read {File.read(File.join(File.dirname(__FILE__), 'fixtures', 'book', 'OPS', '日本語.xhtml'))}
45
+ assert_equal '日本語', content_doc.title
46
+ end
47
+
48
+ def test_title_returns_empty_string_when_title_element_not_exist
49
+ content_doc = XHTML.new
50
+ stub(content_doc).read {'content'}
51
+ assert_equal '', content_doc.title
52
+ end
32
53
  end
data/test/test_epub.rb CHANGED
@@ -12,5 +12,17 @@ class TestEUPB < Test::Unit::TestCase
12
12
  book.parse @file
13
13
  end
14
14
  end
15
+
16
+ def test_each_page_on_spine_returns_enumerator_when_block_not_given
17
+ book = EPUB::Parser.parse(@file)
18
+ assert_kind_of Enumerator, book.each_page_on_spine
19
+ end
20
+
21
+ def test_enumerator_each_page_on_spine_returns_yields_item
22
+ enum = EPUB::Parser.parse(@file).each_page_on_spine
23
+ enum.each do |entry|
24
+ assert_kind_of EPUB::Publication::Package::Manifest::Item, entry
25
+ end
26
+ end
15
27
  end
16
28
 
@@ -1,7 +1,6 @@
1
1
  require_relative 'helper'
2
2
  require 'epub/book'
3
3
  require 'epub/publication'
4
- require 'epub/publication/fixed_layout'
5
4
 
6
5
  class EPUB::Publication::Package
7
6
  include EPUB::Publication::FixedLayout
@@ -0,0 +1,121 @@
1
+ require_relative 'helper'
2
+ require 'epub'
3
+
4
+ class TestInspect < Test::Unit::TestCase
5
+ class TestPackage < TestInspect
6
+ include EPUB::Publication
7
+
8
+ def setup
9
+ @package = Package.new
10
+ end
11
+
12
+ def test_package_inspects_object_id
13
+ assert_match (@package.__id__ << 1).to_s(16), @package.inspect
14
+ end
15
+
16
+ def test_package_inspects_attributes
17
+ @package.xml_lang = "zh"
18
+ @package.prefix = {'foaf' => 'http://xmlns.com/foaf/spec/'}
19
+
20
+ assert_match %Q|@xml_lang="zh"|, @package.inspect
21
+ assert_match %Q|@prefix={"foaf"=>"http://xmlns.com/foaf/spec/"}|, @package.inspect
22
+ end
23
+
24
+ def test_package_inspects_content_models
25
+ @package.metadata = Package::Metadata.new
26
+
27
+ assert_match '@metadata=#<EPUB::Publication::Package::Metadata:', @package.inspect
28
+ end
29
+
30
+ class TestMetadata < TestPackage
31
+ Metadata = Package::Metadata
32
+
33
+ def setup
34
+ super
35
+ @metadata = Metadata.new
36
+ @package.metadata = @metadata
37
+ end
38
+
39
+ def test_inspects_package_simply
40
+ assert_match /@package=\#<EPUB::Publication::Package:[^ ]+>/, @metadata.inspect
41
+ end
42
+
43
+ def test_inspects_attributes
44
+ title = Metadata::Title.new
45
+ title.content = 'Book Title'
46
+ @metadata.titles << title
47
+
48
+ title_pattern = RUBY_VERSION >= '2.0' ? '@dc_titles=[#<EPUB::Publication::Package::Metadata::Title' : 'Book Title'
49
+
50
+ assert_match title_pattern, @metadata.inspect
51
+ end
52
+
53
+ def test_dcmes_inspect_includes_class_name
54
+ meta = Package::Metadata::Title.new
55
+ meta.content = 'Book Title'
56
+
57
+ title_pattern = RUBY_VERSION >= '2.0' ? '#<EPUB::Publication::Package::Metadata::Title' : 'Book Title'
58
+
59
+ assert_match title_pattern, meta.inspect
60
+ end
61
+
62
+ def test_dcmes_inspect_includes_instance_variables
63
+ meta = Package::Metadata::DCMES.new
64
+ meta.lang = 'en-US'
65
+ meta.dir = 'rtl'
66
+
67
+ if RUBY_VERSION >= '2.0'
68
+ assert_match /@lang/, meta.inspect
69
+ assert_match /en\-US/, meta.inspect
70
+ assert_match /@dir/, meta.inspect
71
+ assert_match /rtl/, meta.inspect
72
+ else
73
+ assert_equal '', meta.inspect
74
+ end
75
+ end
76
+
77
+ def test_meta_inspect_includes_class_name
78
+ meta = Package::Metadata::Meta.new
79
+
80
+ assert_match /Package::Metadata::Meta/, meta.inspect
81
+ end
82
+
83
+ def test_meta_inspect_includes_instance_variables
84
+ meta = Package::Metadata::Meta.new
85
+ meta.id = 'meta-id'
86
+ meta.content = 'meta content'
87
+
88
+ assert_match /@id/, meta.inspect
89
+ assert_match /meta\-id/, meta.inspect
90
+ assert_match /@content/, meta.inspect
91
+ assert_match /meta content/, meta.inspect
92
+ end
93
+ end
94
+
95
+ class TestManifest < TestPackage
96
+ Manifest = Package::Manifest
97
+
98
+ def setup
99
+ super
100
+ @manifest = Manifest.new
101
+ @package.manifest = @manifest
102
+ end
103
+
104
+ def test_inspects_package_simply
105
+ assert_match /@package=\#<EPUB::Publication::Package:[^ ]+>/, @manifest.inspect
106
+ end
107
+
108
+ class TestItem < TestManifest
109
+ def setup
110
+ super
111
+ @item = Manifest::Item.new
112
+ @manifest << @item
113
+ end
114
+
115
+ def test_inspects_manifest_simply
116
+ assert_match /\#<EPUB::Publication::Package::Manifest:[^ ]+>/, @item.inspect
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
  require_relative 'helper'
2
3
 
3
4
  class TestParserContentDocument < Test::Unit::TestCase
@@ -27,5 +28,7 @@ class TestParserContentDocument < Test::Unit::TestCase
27
28
  assert_equal @manifest.items.first, nav.items.first.item
28
29
  assert_equal @manifest.items[1], nav.items[1].items[0].item
29
30
  assert_equal @manifest.items[1], nav.items[1].items[1].item
31
+
32
+ assert_equal '第四節', nav.items.last.items.last.text
30
33
  end
31
34
  end
@@ -11,6 +11,6 @@ class TestParserFixedLayout < Test::Unit::TestCase
11
11
  </package>
12
12
  OPF
13
13
  package = parser.parse_package
14
- assert_true package.using_fixed_layout
14
+ assert_true package.using_fixed_layout?
15
15
  end
16
16
  end
@@ -20,7 +20,7 @@ class TestParserOCF < Test::Unit::TestCase
20
20
  def test_parse_container_can_find_primary_rootfile
21
21
  container = @parser.parse_container(@container_xml)
22
22
 
23
- assert_equal 'OPS/ルートファイル.opf', container.rootfile.full_path
23
+ assert_equal 'OPS/ルートファイル.opf', container.rootfile.full_path.to_s
24
24
  end
25
25
 
26
26
  def test_parse_encryption_do_nothing_excluding_to_have_content
@@ -3,16 +3,18 @@ require 'epub/publication'
3
3
 
4
4
  class TestPublication < Test::Unit::TestCase
5
5
  include EPUB::Publication
6
+ def setup
7
+ @package = EPUB::Publication::Package.new
8
+ end
6
9
 
7
10
  def test_package_clear_package_attribute_of_submodules_when_attribute_writer_called
8
11
  metadata = EPUB::Publication::Package::Metadata.new
9
12
  another_metadata = EPUB::Publication::Package::Metadata.new
10
- package = EPUB::Publication::Package.new
11
13
 
12
- package.metadata = metadata
13
- assert_equal metadata.package, package
14
+ @package.metadata = metadata
15
+ assert_equal metadata.package, @package
14
16
 
15
- package.metadata = another_metadata
17
+ @package.metadata = another_metadata
16
18
  assert_nil metadata.package
17
19
  end
18
20
 
@@ -62,6 +64,76 @@ class TestPublication < Test::Unit::TestCase
62
64
 
63
65
  assert_equal 'Extended Title', package.title
64
66
  end
67
+
68
+ def test_title_returns_compositted_title_when_it_is_not_empty
69
+ main_title = Package::Metadata::Title.new
70
+ main_title.id = 'main-title'
71
+ main_title.content = 'main title'
72
+ main_refiner = Package::Metadata::Meta.new
73
+ main_refiner.property = 'title-type'
74
+ main_refiner.content = 'main'
75
+ main_refiner.refines = main_title
76
+ main_order = Package::Metadata::Meta.new
77
+ main_order.property = 'display-seq'
78
+ main_order.content = 1
79
+ main_order.refines = main_title
80
+
81
+ subtitle = Package::Metadata::Title.new
82
+ subtitle.id = 'subtitle'
83
+ subtitle.content = 'subtitle'
84
+ sub_refiner = Package::Metadata::Meta.new
85
+ sub_refiner.property = 'title-type'
86
+ sub_refiner.content = 'subtitle'
87
+ sub_refiner.refines = subtitle
88
+ sub_order = Package::Metadata::Meta.new
89
+ sub_order.property = 'display-seq'
90
+ sub_order.content = 2
91
+ sub_order.refines = subtitle
92
+
93
+ package = Package::Metadata.new
94
+ package.titles << main_title << subtitle
95
+
96
+ assert_equal "main title\nsubtitle", package.title
97
+ end
98
+
99
+ def test_title_returns_main_title_when_no_title_has_order
100
+ main_title = Package::Metadata::Title.new
101
+ main_title.id = 'main-title'
102
+ main_title.content = 'main title'
103
+ main_refiner = Package::Metadata::Meta.new
104
+ main_refiner.property = 'title-type'
105
+ main_refiner.content = 'main'
106
+ main_refiner.refines = main_title
107
+
108
+ subtitle = Package::Metadata::Title.new
109
+ subtitle.id = 'subtitle'
110
+ subtitle.content = 'subtitle'
111
+ sub_refiner = Package::Metadata::Meta.new
112
+ sub_refiner.property = 'title-type'
113
+ sub_refiner.content = 'subtitle'
114
+ sub_refiner.refines = subtitle
115
+
116
+ package = Package::Metadata.new
117
+ package.titles << subtitle << main_title
118
+
119
+ assert_equal "main title", package.title
120
+ end
121
+
122
+ def test_meta_refining_publication_is_primary_expression
123
+ meta = Package::Metadata::Meta.new
124
+ meta.property = 'dcterms:modified'
125
+
126
+ assert_true meta.primary_expression?
127
+ end
128
+
129
+ def test_meta_refining_other_element_is_subexpression
130
+ title = Package::Metadata::Title.new
131
+ title.id = 'title'
132
+ meta = Package::Metadata::Meta.new
133
+ meta.refines = title
134
+
135
+ assert_true meta.subexpression?
136
+ end
65
137
  end
66
138
 
67
139
  class TestManifest < TestPublication
@@ -93,6 +165,20 @@ class TestPublication < Test::Unit::TestCase
93
165
 
94
166
  assert_same itemref, item.itemref
95
167
  end
168
+
169
+ def test_xhtml_returns_true_when_xhtml
170
+ item = Package::Manifest::Item.new
171
+ item.media_type = 'application/xhtml+xml'
172
+
173
+ assert_true item.xhtml?
174
+ end
175
+
176
+ def test_xhtml_returns_false_when_not_xhtml
177
+ item = Package::Manifest::Item.new
178
+ item.media_type = 'text/css'
179
+
180
+ assert_false item.xhtml?
181
+ end
96
182
  end
97
183
  end
98
184
 
@@ -138,6 +224,41 @@ class TestPublication < Test::Unit::TestCase
138
224
  assert_include spine.items, item
139
225
  assert_same item, @itemref.item
140
226
  end
227
+
228
+ def test_itemref_equals_itemref_with_same_attributes
229
+ base = Package::Spine::Itemref.new
230
+ another = Package::Spine::Itemref.new
231
+ [base, another].each do |itemref|
232
+ [:spine, :idref, :id].each do |attr|
233
+ itemref.__send__ "#{attr}=", attr.to_s
234
+ end
235
+ itemref.linear = false
236
+ end
237
+ base.properties = ['property1', 'property2']
238
+ another.properties = ['property2', 'property1']
239
+
240
+ assert_true base == another
241
+
242
+ base.linear = true
243
+ another.linear = 'yes'
244
+
245
+ assert_true base == another
246
+ end
247
+
248
+ def test_itemref_doesnt_equal_itemref_with_different_attributes
249
+ base = Package::Spine::Itemref.new
250
+ another = Package::Spine::Itemref.new
251
+ [base, another].each do |itemref|
252
+ [:spine, :idref, :id].each do |attr|
253
+ itemref.__send__ "#{attr}=", attr.to_s
254
+ end
255
+ itemref.linear = false
256
+ end
257
+ base.properties = ['property1', 'property2']
258
+ another.properties = ['property1', 'property2', 'property3']
259
+
260
+ assert_false base == another
261
+ end
141
262
  end
142
263
  end
143
264
  end