epub-parser 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
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