epub-parser 0.1.0 → 0.1.1

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.
@@ -0,0 +1,3 @@
1
+ [submodule "wiki"]
2
+ path = wiki
3
+ url = git://github.com/KitaitiMakoto/epub-parser.wiki.git
@@ -26,22 +26,30 @@ For more info:
26
26
  # do somethong...
27
27
  end
28
28
 
29
- See the [wiki][] for more info.
30
- Or [API Documentation][rubydoc].
29
+ See the [wiki][] or [API Documentation][rubydoc] for more info.
31
30
 
32
31
  [wiki]: https://github.com/KitaitiMakoto/epub-parser/wiki
33
32
  [rubydoc]: http://rubydoc.info/gems/epub-parser/frames
34
33
 
35
34
  REQUIREMENTS
36
35
  ------------
37
- * libzip for Zip/Ruby gem
38
36
  * libxml2 and libxslt for Nokogiri gem
39
37
 
38
+ CHANGELOG
39
+ ---------
40
+
41
+ ### 0.1.1
42
+ * Parse package@prefix and attach it as `Package#prefix`
43
+ * `Manifest::Item#iri` wes removed. It have existed for files in unzipped epub books but now EPUB Parser retrieves files from zip archive directly. `#href` now returns `Addressable::URI` object.
44
+ * `Metadata::Link#iri`: ditto.
45
+ * `Guide::Reference#iri`: ditto.
46
+
40
47
  TODOS
41
48
  -----
42
- * Adding tests
43
- * Modify methods around fallback to check bindings element in the package
49
+ * Vocabulary Association Mechanisms
44
50
  * Implementing navigation document and so on
51
+ * Fixed Layout
52
+ * Digital Signature
45
53
  * Using SAX on parsing
46
54
  * Extracting and organizing common behavior from some classes to modules
47
55
  * Abstraction of XML parser(making it possible to use REXML, standard bundled XML library of Ruby)
@@ -49,6 +57,7 @@ TODOS
49
57
  DONE
50
58
  ----
51
59
  * Using zip library instead of `unzip` command, which has security issue
60
+ * Modify methods around fallback to see `bindings` element in the package
52
61
 
53
62
  LICENSE
54
63
  -------
data/Rakefile CHANGED
@@ -1,8 +1,10 @@
1
- require 'bundler/gem_tasks'
1
+ require 'bundler/gem_helper'
2
2
  require 'rake/testtask'
3
+ require 'rake/clean'
3
4
  require 'yard'
4
5
  require 'cucumber'
5
6
  require 'cucumber/rake/task'
7
+ require 'epub/parser/version'
6
8
 
7
9
  task :default => :test
8
10
  task :test => 'test:default'
@@ -19,13 +21,31 @@ namespace :test do
19
21
  desc 'Build the test fixture EPUB'
20
22
  task :build do
21
23
  input_dir = 'test/fixtures/book'
22
- output_dir = 'test/fixtures/'
23
24
  FileList["#{input_dir}/**/*"]
24
25
  sh "epzip #{input_dir}"
25
26
  end
26
27
  end
27
28
 
28
29
 
29
- YARD::Rake::YardocTask.new
30
+ YARD::Rake::YardocTask.new do |task|
31
+ task.files = %w[- wiki/*.md]
32
+ end
33
+
34
+ gem_helper = Bundler::GemHelper.new
35
+
36
+ desc "Build epub-parser-#{EPUB::Parser::VERSION}.gem into the pkg directory."
37
+ task :build => :yard do
38
+ gem_helper.build_gem
39
+ end
40
+
41
+ desc "Build and install epub-parser-#{EPUB::Parser::VERSION}.gem into system gems."
42
+ task :install => :yard do
43
+ gem_helper.install_gem
44
+ end
45
+
46
+ desc "Create tag v#{EPUB::Parser::VERSION} and build and push epub-parser-#{EPUB::Parser::VERSION}.gem to Rubygems"
47
+ task :release => :yard do
48
+ gem_helper.release_gem
49
+ end
30
50
 
31
51
  Cucumber::Rake::Task.new
@@ -10,7 +10,10 @@ Usage: epubinfo [options] EPUBFILE
10
10
 
11
11
  EOB
12
12
  opt.version = EPUB::Parser::VERSION
13
- opt.on '-f', '--format=FORMAT', [:line, :json, :yaml], 'format of output(line, json or yaml), defaults to line(for console)' do |format|
13
+ formats = [:line, :json, :yaml]
14
+ nl_formats = formats.dup
15
+ nl_last = nl_formats.pop
16
+ opt.on '-f', '--format=FORMAT', formats, "format of output(#{nl_formats.join(', ')} or #{nl_last}), defaults to line(for console)" do |format|
14
17
  options[:format] = format
15
18
  end
16
19
  end
@@ -14,7 +14,9 @@ Gem::Specification.new do |s|
14
14
 
15
15
  # s.rubyforge_project = "epub-parser"
16
16
 
17
- s.files = `git ls-files`.split("\n").push('test/fixtures/book/OPS/ルートファイル.opf')
17
+ s.files = `git ls-files`.split("\n")
18
+ .push('test/fixtures/book/OPS/ルートファイル.opf')
19
+ .push(Dir['doc/*'])
18
20
  s.files.delete('"test/fixtures/book/OPS/\343\203\253\343\203\274\343\203\210\343\203\225\343\202\241\343\202\244\343\203\253.opf"')
19
21
  s.test_files = `git ls-files -- {test,spec,features}/**/*.rb`.split("\n")
20
22
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
@@ -20,14 +20,20 @@ module EPUB
20
20
  Parser.parse(file, options)
21
21
  end
22
22
 
23
+ Publication::Package::CONTENT_MODELS.each do |model|
24
+ define_method model do
25
+ package.__send__(model)
26
+ end
27
+ end
28
+
23
29
  %w[ title main_title subtitle short_title collection_title edition_title extended_title ].each do |met|
24
30
  define_method met do
25
- @package.metadata.__send__(met)
31
+ metadata.__send__(met)
26
32
  end
27
33
  end
28
34
 
29
35
  def each_page_on_spine(&blk)
30
- enum = @package.spine.items
36
+ enum = package.spine.items
31
37
  if block_given?
32
38
  enum.each &blk
33
39
  else
@@ -36,10 +42,11 @@ module EPUB
36
42
  end
37
43
 
38
44
  def each_page_on_toc(&blk)
45
+ raise NotImplementedError
39
46
  end
40
47
 
41
48
  def each_content(&blk)
42
- enum = @package.manifest.items
49
+ enum = manifest.items
43
50
  if block_given?
44
51
  enum.each &blk
45
52
  else
@@ -48,10 +55,11 @@ module EPUB
48
55
  end
49
56
 
50
57
  def other_navigation
58
+ raise NotImplementedError
51
59
  end
52
60
 
53
61
  def resources
54
- @package.manifest.items
62
+ manifest.items
55
63
  end
56
64
 
57
65
  # Syntax sugar
@@ -61,6 +69,6 @@ module EPUB
61
69
 
62
70
  # Syntax sugar
63
71
  def cover_image
64
- package.manifest.cover_image
72
+ manifest.cover_image
65
73
  end
66
74
  end
@@ -10,15 +10,10 @@ module EPUB
10
10
  'svg' => 'http://www.w3.org/2000/svg'
11
11
  }
12
12
 
13
- module Type
14
- TOC = 'toc'
15
- PAGE_LIST = 'page_list'
16
- LANDMARKS = 'landmarks'
17
- end
18
-
19
13
  module MediaType
20
14
  class UnsupportedError < StandardError; end
21
15
 
16
+ ROOTFILE = 'application/oebps-package+xml'
22
17
  IMAGE = %w[
23
18
  image/gif
24
19
  image/jpeg
@@ -1,6 +1,12 @@
1
1
  module EPUB
2
2
  module ContentDocument
3
3
  class Navigation
4
+ module Type
5
+ TOC = 'toc'
6
+ PAGE_LIST = 'page_list'
7
+ LANDMARKS = 'landmarks'
8
+ end
9
+
4
10
  attr_accessor :navs
5
11
  alias navigations navs
6
12
  alias navigations= navs=
@@ -3,7 +3,7 @@ module EPUB
3
3
  class Container
4
4
  FILE = 'container.xml'
5
5
 
6
- attr_accessor :rootfiles
6
+ attr_reader :rootfiles
7
7
 
8
8
  def initialize
9
9
  @rootfiles = []
@@ -16,6 +16,10 @@ module EPUB
16
16
 
17
17
  class Rootfile
18
18
  attr_accessor :full_path, :media_type
19
+
20
+ def initialize(full_path=nil, media_type=EPUB::MediaType::ROOTFILE)
21
+ @full_path, @media_type = full_path, media_type
22
+ end
19
23
  end
20
24
  end
21
25
  end
@@ -1,6 +1,7 @@
1
1
  module EPUB
2
2
  class OCF
3
3
  class Encryption
4
+ attr_accessor :content
4
5
  end
5
6
  end
6
7
  end
@@ -18,7 +18,7 @@ module EPUB
18
18
  # @param [Nokogiri::HTML::Document] document HTML document or element including nav
19
19
  # @return [Array<EPUB::ContentDocument::Navigation::Nav>] navs array of Nav object
20
20
  def parse_navigations(document)
21
- navs = document.search('/xhtml:html/xhtml:body//xhtml:nav', EPUB::NAMESPACES).collect {|elem| parse_navigation elem}
21
+ document.search('/xhtml:html/xhtml:body//xhtml:nav', EPUB::NAMESPACES).collect {|elem| parse_navigation elem}
22
22
  end
23
23
 
24
24
  # @param [Nokogiri::XML::Element] nav nav element
@@ -21,11 +21,14 @@ module EPUB
21
21
  end
22
22
 
23
23
  def parse
24
- container_xml = @zip.fopen(File.join(DIRECTORY, CONTAINER_FILE)).read
25
- @ocf.container = parse_container(container_xml)
26
- (EPUB::OCF::MODULES - ['container']).each do |m|
27
- @ocf.__send__ "#{m}=", __send__("parse_#{m}")
24
+ EPUB::OCF::MODULES.each do |m|
25
+ begin
26
+ file = @zip.fopen(File.join(DIRECTORY, self.class.const_get("#{m.upcase}_FILE")))
27
+ @ocf.__send__ "#{m}=", __send__("parse_#{m}", file.read)
28
+ rescue Zip::Error
29
+ end
28
30
  end
31
+
29
32
  @ocf
30
33
  end
31
34
 
@@ -43,8 +46,10 @@ module EPUB
43
46
  container
44
47
  end
45
48
 
46
- def parse_encryption
47
- warn "Not implemented: #{self.class}##{__method__}" if $VERBOSE
49
+ def parse_encryption(content)
50
+ encryption = EPUB::OCF::Encryption.new
51
+ encryption.content = content
52
+ encryption
48
53
  end
49
54
 
50
55
  def parse_manifest
@@ -1,3 +1,4 @@
1
+ require 'strscan'
1
2
  require 'zipruby'
2
3
  require 'nokogiri'
3
4
  require 'addressable/uri'
@@ -33,8 +34,12 @@ module EPUB
33
34
 
34
35
  def parse_package
35
36
  elem = @doc.root
36
- @package.version = elem['version']
37
- @package.unique_identifier_id = elem['unique-identifier']
37
+ %w[version xml:lang dir id].each do |attr|
38
+ writer = attr.gsub(/\:/, '_') + '='
39
+ @package.__send__(writer, elem[attr])
40
+ end
41
+ @unique_identifier_id = elem['unique-identifier']
42
+ @package.prefix = parse_prefix(elem['prefix'])
38
43
 
39
44
  @package
40
45
  end
@@ -45,10 +50,10 @@ module EPUB
45
50
  id_map = {}
46
51
 
47
52
  metadata.identifiers = elem.xpath('./dc:identifier', EPUB::NAMESPACES).collect do |e|
48
- identifier = EPUB::Publication::Package::Metadata::Identifier.new
53
+ identifier = EPUB::Publication::Package::Metadata::DCMES.new
49
54
  identifier.content = e.content
50
55
  identifier.id = id = e['id']
51
- metadata.unique_identifier = identifier if id == @package.unique_identifier_id
56
+ metadata.unique_identifier = identifier if id == @unique_identifier_id
52
57
 
53
58
  identifier
54
59
  end
@@ -95,10 +100,10 @@ module EPUB
95
100
 
96
101
  metadata.links = elem.xpath('./opf:link', EPUB::NAMESPACES).collect do |e|
97
102
  link = EPUB::Publication::Package::Metadata::Link.new
98
- %w[ href id media-type ].each do |attr|
103
+ %w[ id media-type ].each do |attr|
99
104
  link.__send__(attr.gsub(/-/, '_') + '=', e[attr])
100
105
  end
101
- link.iri = Addressable::URI.parse(e['href'])
106
+ link.href = Addressable::URI.parse(e['href'])
102
107
  link.rel = e['rel'].strip.split
103
108
  if (refines = e['refines']) && refines[0] == '#'
104
109
  id = refines[1..-1]
@@ -132,8 +137,7 @@ module EPUB
132
137
  %w[ id media-type media-overlay ].each do |attr|
133
138
  item.__send__("#{attr.gsub(/-/, '_')}=", e[attr])
134
139
  end
135
- item.href = e['href']
136
- item.iri = @rootfile.join Addressable::URI.parse(e['href'])
140
+ item.href = Addressable::URI.parse(e['href'])
137
141
  fallback_map[e['fallback']] = item if e['fallback']
138
142
  item.properties = e['properties'] ? e['properties'].split(' ') : []
139
143
  manifest << item
@@ -169,10 +173,10 @@ module EPUB
169
173
  guide = @package.guide = EPUB::Publication::Package::Guide.new
170
174
  @doc.xpath('/opf:package/opf:guide/opf:reference', EPUB::NAMESPACES).each do |ref|
171
175
  reference = EPUB::Publication::Package::Guide::Reference.new
172
- %w[ type title href ].each do |attr|
176
+ %w[ type title ].each do |attr|
173
177
  reference.__send__("#{attr}=", ref[attr])
174
178
  end
175
- reference.iri = @rootfile.join Addressable::URI.parse(reference.href)
179
+ reference.href = Addressable::URI.parse(ref['href'])
176
180
  guide << reference
177
181
  end
178
182
 
@@ -185,14 +189,31 @@ module EPUB
185
189
  media_type = EPUB::Publication::Package::Bindings::MediaType.new
186
190
  media_type.media_type = elem['media-type']
187
191
  items = @package.manifest.items
188
- index = items.index {|item| item.id == elem['handler']}
189
- media_type.handler = items[index] if index
192
+ media_type.handler = items.detect {|item| item.id == elem['handler']}
190
193
  bindings << media_type
191
194
  end
192
195
 
193
196
  bindings
194
197
  end
195
198
 
199
+ def parse_prefix(str)
200
+ prefixes = {}
201
+ return prefixes if str.nil? or str.empty?
202
+ scanner = StringScanner.new(str)
203
+ scanner.scan /\s*/
204
+ while prefix = scanner.scan(/[^\:\s]+/)
205
+ scanner.scan /[\:\s]+/
206
+ iri = scanner.scan(/[^\s]+/)
207
+ if iri.nil? or iri.empty?
208
+ warn "no IRI detected for prefix `#{prefix}`"
209
+ else
210
+ prefixes[prefix] = iri
211
+ end
212
+ scanner.scan /\s*/
213
+ end
214
+ prefixes
215
+ end
216
+
196
217
  def collect_dcmes(elem, selector)
197
218
  elem.xpath(selector, EPUB::NAMESPACES).collect do |e|
198
219
  md = EPUB::Publication::Package::Metadata::DCMES.new
@@ -1,5 +1,5 @@
1
1
  module EPUB
2
2
  class Parser
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.1"
4
4
  end
5
5
  end
@@ -1,6 +1 @@
1
1
  require 'epub/publication/package'
2
-
3
- module EPUB
4
- module Publication
5
- end
6
- end
@@ -1,37 +1,36 @@
1
- %w[ metadata manifest spine guide bindings ].each { |f| require "epub/publication/package/#{f}" }
2
-
3
1
  module EPUB
4
2
  module Publication
5
3
  class Package
6
- attr_accessor :book,
7
- :version, :unique_identifier_id, :prefix, :xml_lang, :dir, :id
8
- attr_reader :metadata, :manifest, :spine, :guide, :bindings
9
- alias lang xml_lang
10
- alias lang= xml_lang=
4
+ CONTENT_MODELS = [:metadata, :manifest, :spine, :guide, :bindings]
5
+ RESERVED_VOCABULARY_PREFIXES = {
6
+ '' => 'http://idpf.org/epub/vocab/package/#',
7
+ 'dcterms' => 'http://purl.org/dc/terms/',
8
+ 'marc' => 'http://id.loc.gov/vocabulary/',
9
+ 'media' => 'http://www.idpf.org/epub/vocab/overlays/#',
10
+ 'onix' => 'http://www.editeur.org/ONIX/book/codelists/current.html#',
11
+ 'xsd' => 'http://www.w3.org/2001/XMLSchema#'
12
+ }
11
13
 
12
- def metadata=(metadata)
13
- metadata.package = self
14
- @metadata = metadata
15
- end
16
-
17
- def manifest=(manifest)
18
- manifest.package = self
19
- @manifest = manifest
20
- end
21
14
 
22
- def spine=(spine)
23
- spine.package = self
24
- @spine = spine
15
+ class << self
16
+ def define_content_model(model_name)
17
+ define_method "#{model_name}=" do |model|
18
+ current_model = __send__(model_name)
19
+ current_model.package = nil if current_model
20
+ model.package = self
21
+ instance_variable_set "@#{model_name}", model
22
+ end
23
+ end
25
24
  end
26
25
 
27
- def guide=(guide)
28
- guide.package = self
29
- @guide = guide
30
- end
26
+ attr_accessor :book,
27
+ :version, :prefix, :xml_lang, :dir, :id
28
+ attr_reader *CONTENT_MODELS
29
+ alias lang xml_lang
30
+ alias lang= xml_lang=
31
31
 
32
- def bindings=(bindings)
33
- bindings.package = self
34
- @buindings = bindings
32
+ CONTENT_MODELS.each do |model|
33
+ define_content_model model
35
34
  end
36
35
 
37
36
  def unique_identifier
@@ -40,3 +39,7 @@ module EPUB
40
39
  end
41
40
  end
42
41
  end
42
+
43
+ EPUB::Publication::Package::CONTENT_MODELS.each do |f|
44
+ require_relative "package/#{f}"
45
+ end
@@ -2,12 +2,20 @@ module EPUB
2
2
  module Publication
3
3
  class Package
4
4
  class Bindings
5
- attr_accessor :package,
6
- :media_types
5
+ attr_accessor :package
7
6
 
8
7
  def <<(media_type)
9
- @media_types ||= []
10
- @media_types << media_type
8
+ @media_types ||= {}
9
+ @media_types[media_type.media_type] = media_type
10
+ end
11
+
12
+ def [](media_type)
13
+ _, mt = @media_types.detect {|key, _| key == media_type}
14
+ mt
15
+ end
16
+
17
+ def media_types
18
+ @media_types.values
11
19
  end
12
20
 
13
21
  class MediaType
@@ -16,26 +16,26 @@ module EPUB
16
16
  end
17
17
 
18
18
  %w[cover title-page toc index glossary acknowledgements bibliography colophon copyright-page dedication epigraph foreword loi lot notes preface text].each do |type|
19
- define_method type do
20
- var = instance_variable_get "@#{type}"
19
+ method_name = type.gsub('-', '_')
20
+ define_method method_name do
21
+ var = instance_variable_get "@#{method_name}"
21
22
  return var if var
22
23
 
23
- var = references.selector {|ref| ref.type == type.to_s}.first
24
- instance_variable_set "@#{type}", var
24
+ var = references.selector {|ref| ref.type == type}.first
25
+ instance_variable_set "@#{method_name}", var
25
26
  end
26
27
  end
27
28
 
28
29
  class Reference
29
30
  attr_accessor :guide,
30
- :type, :title, :href,
31
- :iri
31
+ :type, :title, :href
32
32
 
33
33
  def item
34
34
  return @item if @item
35
35
 
36
- len = iri.fragment.nil? ? 1 : iri.fragment.length + 2
36
+ request_uri = href.request_uri
37
37
  @item = @guide.package.manifest.items.selector do |item|
38
- item.href == href[0 .. -len]
38
+ item.href.request_uri == request_uri
39
39
  end.first
40
40
  end
41
41
  end
@@ -28,7 +28,7 @@ module EPUB
28
28
  end
29
29
 
30
30
  def items
31
- @items.collect {|id, item| item}
31
+ @items.values
32
32
  end
33
33
 
34
34
  def [](item_id)
@@ -36,23 +36,37 @@ module EPUB
36
36
  end
37
37
 
38
38
  class Item
39
+ # @!attribute [rw] manifest
40
+ # @return [Manifest] Returns the value of manifest
41
+ # @!attribute [rw] id
42
+ # @return [String] Returns the value of id
43
+ # @!attribute [rw] href
44
+ # @return [Addressable::URI] Returns the value of href
45
+ # @!attribute [rw] media_type
46
+ # @return [String] Returns the value of media_type
47
+ # @!attribute [rw] properties
48
+ # @return [Array<String>] Returns the value of properties
49
+ # @!attribute [rw] media_overlay
50
+ # @return [String] Returns the value of media_overlay
51
+ # @!attribute [rw] fallback
52
+ # @return [Item] Returns the value of attribute fallback
39
53
  attr_accessor :manifest,
40
- :id, :href, :media_type, :fallback, :properties, :media_overlay,
41
- :iri
54
+ :id, :href, :media_type, :fallback, :properties, :media_overlay
42
55
 
43
- # To do: Handle circular fallback chain
56
+ # @todo Handle circular fallback chain
44
57
  def fallback_chain
45
- return @fallback_chain if @fallback_chain
46
- @fallback_chain = traverse_fallback_chain([])
58
+ @fallback_chain ||= traverse_fallback_chain([])
47
59
  end
48
60
 
49
61
  def read
62
+ rootfile = Addressable::URI.parse(manifest.package.book.ocf.container.rootfile.full_path)
50
63
  Zip::Archive.open(manifest.package.book.epub_file) {|zip|
51
- zip.fopen(iri.to_s).read
64
+ path = rootfile + href.request_uri
65
+ zip.fopen(path.to_s).read
52
66
  }
53
67
  end
54
68
 
55
- # To do: Handle circular fallback chain
69
+ # @todo Handle circular fallback chain
56
70
  def use_fallback_chain(options = {})
57
71
  supported = EPUB::MediaType::CORE
58
72
  if ad = options[:supported]
@@ -62,13 +76,12 @@ module EPUB
62
76
  supported = supported - (del.respond_to?(:to_ary) ? del : [del])
63
77
  end
64
78
 
65
- if supported.include? media_type
66
- yield self
67
- elsif fallback
68
- fallback.use_fallback_chain(options) {|fb| yield fb}
69
- else
70
- raise EPUB::MediaType::UnsupportedError
79
+ return yield self if supported.include? media_type
80
+ if (bindings = manifest.package.bindings) && (binding_media_type = bindings[media_type])
81
+ return yield binding_media_type.handler
71
82
  end
83
+ return fallback.use_fallback_chain(options) {|fb| yield fb} if fallback
84
+ raise EPUB::MediaType::UnsupportedError
72
85
  end
73
86
 
74
87
  protected
@@ -12,6 +12,12 @@ module EPUB
12
12
  alias_method "#{elem}=", "dc_#{elem}="
13
13
  end
14
14
 
15
+ def initialize
16
+ (DC_ELEMS + [:metas, :links]).each do |elem|
17
+ __send__ "#{elem}=", []
18
+ end
19
+ end
20
+
15
21
  def title
16
22
  return extended_title unless extended_title.empty?
17
23
  compositted = titles.select {|title| title.display_seq}.sort.join("\n")
@@ -41,14 +47,14 @@ module EPUB
41
47
  end
42
48
 
43
49
  module Refinable
50
+ PROPERTIES = %w[ alternate-script display-seq file-as group-position identifier-type meta-auth role title-type ]
51
+
44
52
  attr_writer :refiners
45
53
 
46
54
  def refiners
47
55
  @refiners ||= []
48
56
  end
49
57
 
50
- PROPERTIES = %w[ alternate-script display-seq file-as group-position identifier-type meta-auth role title-type ]
51
-
52
58
  PROPERTIES.each do |voc|
53
59
  met = voc.gsub(/-/, '_')
54
60
  attr_writer met
@@ -58,41 +64,24 @@ module EPUB
58
64
  end
59
65
  end
60
66
 
61
- class Identifier
67
+ class DCMES
62
68
  include Refinable
63
69
 
64
- attr_accessor :content, :id
70
+ attr_accessor :content, :id, :lang, :dir
65
71
 
66
72
  def to_s
67
73
  content
68
74
  end
69
75
  end
70
76
 
71
- class Title
72
- include Refinable
77
+ class Title < DCMES
73
78
  include Comparable
74
79
 
75
- attr_accessor :content, :id, :lang, :dir
76
-
77
80
  def <=>(other)
78
81
  return 1 if other.display_seq.nil?
79
82
  return -1 if display_seq.nil?
80
83
  display_seq.to_s.to_i <=> other.display_seq.to_s.to_i
81
84
  end
82
-
83
- def to_s
84
- content
85
- end
86
- end
87
-
88
- class DCMES
89
- include Refinable
90
-
91
- attr_accessor :content, :id, :lang, :dir
92
-
93
- def to_s
94
- content
95
- end
96
85
  end
97
86
 
98
87
  class Meta
@@ -118,8 +107,7 @@ module EPUB
118
107
  class Link
119
108
  include Refinable
120
109
 
121
- attr_accessor :href, :rel, :id, :refines, :media_type,
122
- :iri
110
+ attr_accessor :href, :rel, :id, :refines, :media_type
123
111
  end
124
112
  end
125
113
  end
@@ -40,6 +40,12 @@ module EPUB
40
40
  def item
41
41
  @item ||= @spine.package.manifest[idref]
42
42
  end
43
+
44
+ def ==(other)
45
+ [:spine, :idref, :linear, :id].all? {|meth|
46
+ self.__send__(meth) == other.__send__(meth)
47
+ } and (other.properties - properties).empty?
48
+ end
43
49
  end
44
50
  end
45
51
  end
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE html>
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
4
+ <head>
5
+ <title>LARGE FILE NAME</title>
6
+ </head>
7
+ <body>
8
+ </body>
9
+ </html>
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE html>
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
4
+ <head>
5
+ <title>small file name</title>
6
+ </head>
7
+ <body>
8
+ </body>
9
+ </html>
@@ -1,7 +1,9 @@
1
1
  <?xml version="1.0"?>
2
2
  <package version="3.0"
3
3
  unique-identifier="pub-id"
4
- xmlns="http://www.idpf.org/2007/opf">
4
+ xmlns="http://www.idpf.org/2007/opf"
5
+ prefix=" foaf: http://xmlns.com/foaf/spec/
6
+ dbp: http://dbpedia.org/ontology/ ">
5
7
  <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
6
8
  <dc:identifier id="pub-id">da265185-8da8-462d-a146-17dd388f61fc</dc:identifier>
7
9
 
@@ -57,6 +59,12 @@
57
59
  href="item-2.xhtml"
58
60
  media-type="application/pdf"
59
61
  fallback="manifest-item-fallback"/>
62
+ <item id="large-file-name"
63
+ href="CASE-SENSITIVE.xhtml"
64
+ media-type="application/xhtml+xml"/>
65
+ <item id="small-file-name"
66
+ href="case-sensitive.xhtml"
67
+ media-type="application/xhtml+xml"/>
60
68
  <item id="impl"
61
69
  href="impl.xhtml"
62
70
  media-type="application/xhtml+xml"
@@ -24,6 +24,12 @@ class TestParserOCF < Test::Unit::TestCase
24
24
  assert_equal 'OPS/ルートファイル.opf', container.rootfile.full_path
25
25
  end
26
26
 
27
+ def test_parse_encryption_do_nothing_excluding_to_have_content
28
+ encryption = @parser.parse_encryption('content')
29
+
30
+ assert_equal 'content', encryption.content
31
+ end
32
+
27
33
  def test_parse
28
34
  assert_nothing_raised do
29
35
  @parser.parse
@@ -20,6 +20,17 @@ class TestParserPublication < Test::Unit::TestCase
20
20
  assert_equal '3.0', @package.version
21
21
  end
22
22
 
23
+ def test_has_unique_identifier
24
+ @package.metadata = @parser.parse_metadata
25
+ assert_equal 'pub-id', @package.unique_identifier.id
26
+ assert_equal 'da265185-8da8-462d-a146-17dd388f61fc', @package.unique_identifier.to_s
27
+ end
28
+
29
+ def test_has_prefixes_for_vocabulary
30
+ assert_equal ({'foaf' => 'http://xmlns.com/foaf/spec/', 'dbp' => 'http://dbpedia.org/ontology/'}),
31
+ @package.prefix
32
+ end
33
+
23
34
  class TestParseMetadata < TestParserPublication
24
35
  def setup
25
36
  super
@@ -37,6 +48,21 @@ class TestParserPublication < Test::Unit::TestCase
37
48
  def test_has_five_titles
38
49
  assert_equal 5, @metadata.titles.length
39
50
  end
51
+
52
+ def test_returns_extended_title_as_title_attribute_if_exists
53
+ assert_equal 'The Great Cookbooks of the World:
54
+ Mon premier guide de cuisson, un Mémoire.
55
+ The New French Cuisine Masters, Volume Two.
56
+ Special Anniversary Edition', @metadata.title
57
+ end
58
+
59
+ def test_titles_has_order
60
+ titles = @metadata.titles
61
+ assert titles[0] > titles[1]
62
+ assert titles[1] < titles[2]
63
+ assert titles[2] < titles[3]
64
+ assert titles[3] > titles[4]
65
+ end
40
66
  end
41
67
 
42
68
  class TestParseManifest < TestParserPublication
@@ -45,12 +71,12 @@ class TestParserPublication < Test::Unit::TestCase
45
71
  @manifest = @parser.parse_manifest
46
72
  end
47
73
 
48
- def test_manifest_has_10_items
49
- assert_equal 10, @manifest.items.length
74
+ def test_manifest_has_12_items
75
+ assert_equal 12, @manifest.items.length
50
76
  end
51
77
 
52
- def test_item_has_relative_path_as_iri_attribute
53
- assert_equal 'OPS/nav.xhtml', @manifest['nav'].iri.to_s
78
+ def test_item_has_relative_path_as_href_attribute
79
+ assert_equal 'nav.xhtml', @manifest['nav'].href.to_s
54
80
  end
55
81
 
56
82
  def test_fallback_attribute_of_item_should_be_item_object
@@ -61,16 +87,18 @@ class TestParserPublication < Test::Unit::TestCase
61
87
  end
62
88
 
63
89
  def test_item_is_readable
64
- book = Object.new
65
- mock(@package).book {book}
66
- mock(book).epub_file {'test/fixtures/book.epub'}
67
-
68
- item = @manifest.items.first
90
+ item = EPUB::Parser.parse('test/fixtures/book.epub').package.manifest.items.first
69
91
  doc = Nokogiri.XML item.read
70
92
 
71
93
  assert_equal 'html', doc.root.name
72
94
  end
73
95
 
96
+ def test_iri_of_item_is_case_sensitive
97
+ manifest = EPUB::Parser.parse('test/fixtures/book.epub').package.manifest
98
+
99
+ assert_not_equal manifest['large-file-name'].read, manifest['small-file-name'].read
100
+ end
101
+
74
102
  def test_item_can_traverse_fallback_chain
75
103
  assert_equal [@manifest['manifest-item-2'], @manifest['manifest-item-fallback'], @manifest['manifest-item-fallback2']],
76
104
  @manifest['manifest-item-2'].fallback_chain
@@ -113,7 +141,27 @@ class TestParserPublication < Test::Unit::TestCase
113
141
 
114
142
  def test_item_with_absolute_iri_as_href_must_keep_it
115
143
  item = @manifest['external-css']
116
- assert_equal 'http://example.net/stylesheets/common.css', item.iri.to_s
144
+ assert_equal 'http://example.net/stylesheets/common.css', item.href.to_s
145
+ end
146
+ end
147
+
148
+ class TestParseSpine < TestParserPublication
149
+ def setup
150
+ super
151
+ @spine = @parser.parse_spine
152
+ end
153
+
154
+ def test_each_itemref_yields_itemref_in_order_on_spine_element
155
+ expected = %w[nav manifest-item-1 manifest-item-2].map {|idref|
156
+ itemref = EPUB::Publication::Package::Spine::Itemref.new
157
+ itemref.id = nil
158
+ itemref.spine = @spine
159
+ itemref.idref = idref
160
+ itemref.linear = true
161
+ itemref.properties = []
162
+ itemref
163
+ }
164
+ assert_equal expected, @spine.each_itemref.to_a
117
165
  end
118
166
  end
119
167
 
@@ -155,6 +203,12 @@ class TestParserPublication < Test::Unit::TestCase
155
203
  assert_equal 1, @bindings.media_types.length
156
204
  end
157
205
 
206
+ def test_bindings_is_accessible_like_hash
207
+ media_type = @bindings.media_types.first
208
+ assert_equal media_type, @bindings['application/x-demo-slideshow']
209
+ assert_nil @bindings['non-existing-media-type']
210
+ end
211
+
158
212
  def test_media_type_has_media_type_attribute
159
213
  assert_equal 'application/x-demo-slideshow', @bindings.media_types.first.media_type
160
214
  end
@@ -166,5 +220,12 @@ class TestParserPublication < Test::Unit::TestCase
166
220
  def test_media_type_refers_item_as_handler
167
221
  assert_kind_of EPUB::Publication::Package::Manifest::Item, @bindings.media_types.first.handler
168
222
  end
223
+
224
+ def test_use_fallback_chain_use_bindings
225
+ item = @package.manifest['slideshow']
226
+ item.use_fallback_chain do |slideshow|
227
+ assert_equal 'impl', slideshow.id
228
+ end
229
+ end
169
230
  end
170
231
  end
@@ -0,0 +1,16 @@
1
+ require_relative 'helper'
2
+ require 'epub/publication'
3
+
4
+ class TestPublication < Test::Unit::TestCase
5
+ def test_package_clear_package_attribute_of_submodules_when_attribute_writer_called
6
+ metadata = EPUB::Publication::Package::Metadata.new
7
+ another_metadata = EPUB::Publication::Package::Metadata.new
8
+ package = EPUB::Publication::Package.new
9
+
10
+ package.metadata = metadata
11
+ assert_equal metadata.package, package
12
+
13
+ package.metadata = another_metadata
14
+ assert_nil metadata.package
15
+ end
16
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: epub-parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-23 00:00:00.000000000Z
12
+ date: 2012-12-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rubygems-test
16
- requirement: &14556200 !ruby/object:Gem::Requirement
16
+ requirement: &14987420 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *14556200
24
+ version_requirements: *14987420
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &14555160 !ruby/object:Gem::Requirement
27
+ requirement: &14986340 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *14555160
35
+ version_requirements: *14986340
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: pry
38
- requirement: &14553880 !ruby/object:Gem::Requirement
38
+ requirement: &14984920 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *14553880
46
+ version_requirements: *14984920
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: pry-doc
49
- requirement: &14552820 !ruby/object:Gem::Requirement
49
+ requirement: &15155000 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *14552820
57
+ version_requirements: *15155000
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: test-unit-full
60
- requirement: &14835840 !ruby/object:Gem::Requirement
60
+ requirement: &15152760 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *14835840
68
+ version_requirements: *15152760
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: simplecov
71
- requirement: &14832360 !ruby/object:Gem::Requirement
71
+ requirement: &15151200 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *14832360
79
+ version_requirements: *15151200
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: thin
82
- requirement: &14761180 !ruby/object:Gem::Requirement
82
+ requirement: &15148720 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *14761180
90
+ version_requirements: *15148720
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: yard
93
- requirement: &14760040 !ruby/object:Gem::Requirement
93
+ requirement: &15163320 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *14760040
101
+ version_requirements: *15163320
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: gem-man
104
- requirement: &14758040 !ruby/object:Gem::Requirement
104
+ requirement: &15162500 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *14758040
112
+ version_requirements: *15162500
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: ronn
115
- requirement: &14756820 !ruby/object:Gem::Requirement
115
+ requirement: &15161460 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: '0'
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *14756820
123
+ version_requirements: *15161460
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: epzip
126
- requirement: &14791880 !ruby/object:Gem::Requirement
126
+ requirement: &15160700 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ! '>='
@@ -131,10 +131,10 @@ dependencies:
131
131
  version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
- version_requirements: *14791880
134
+ version_requirements: *15160700
135
135
  - !ruby/object:Gem::Dependency
136
136
  name: epubcheck
137
- requirement: &14790180 !ruby/object:Gem::Requirement
137
+ requirement: &15160160 !ruby/object:Gem::Requirement
138
138
  none: false
139
139
  requirements:
140
140
  - - ! '>='
@@ -142,10 +142,10 @@ dependencies:
142
142
  version: '0'
143
143
  type: :development
144
144
  prerelease: false
145
- version_requirements: *14790180
145
+ version_requirements: *15160160
146
146
  - !ruby/object:Gem::Dependency
147
147
  name: epub_validator
148
- requirement: &14789060 !ruby/object:Gem::Requirement
148
+ requirement: &15159440 !ruby/object:Gem::Requirement
149
149
  none: false
150
150
  requirements:
151
151
  - - ! '>='
@@ -153,10 +153,10 @@ dependencies:
153
153
  version: '0'
154
154
  type: :development
155
155
  prerelease: false
156
- version_requirements: *14789060
156
+ version_requirements: *15159440
157
157
  - !ruby/object:Gem::Dependency
158
158
  name: aruba
159
- requirement: &14786300 !ruby/object:Gem::Requirement
159
+ requirement: &15158500 !ruby/object:Gem::Requirement
160
160
  none: false
161
161
  requirements:
162
162
  - - ! '>='
@@ -164,10 +164,10 @@ dependencies:
164
164
  version: '0'
165
165
  type: :development
166
166
  prerelease: false
167
- version_requirements: *14786300
167
+ version_requirements: *15158500
168
168
  - !ruby/object:Gem::Dependency
169
169
  name: enumerabler
170
- requirement: &13965260 !ruby/object:Gem::Requirement
170
+ requirement: &15157640 !ruby/object:Gem::Requirement
171
171
  none: false
172
172
  requirements:
173
173
  - - ! '>='
@@ -175,10 +175,10 @@ dependencies:
175
175
  version: '0'
176
176
  type: :runtime
177
177
  prerelease: false
178
- version_requirements: *13965260
178
+ version_requirements: *15157640
179
179
  - !ruby/object:Gem::Dependency
180
180
  name: zipruby
181
- requirement: &13963160 !ruby/object:Gem::Requirement
181
+ requirement: &15157120 !ruby/object:Gem::Requirement
182
182
  none: false
183
183
  requirements:
184
184
  - - ! '>='
@@ -186,10 +186,10 @@ dependencies:
186
186
  version: '0'
187
187
  type: :runtime
188
188
  prerelease: false
189
- version_requirements: *13963160
189
+ version_requirements: *15157120
190
190
  - !ruby/object:Gem::Dependency
191
191
  name: nokogiri
192
- requirement: &13962300 !ruby/object:Gem::Requirement
192
+ requirement: &15156560 !ruby/object:Gem::Requirement
193
193
  none: false
194
194
  requirements:
195
195
  - - ! '>='
@@ -197,10 +197,10 @@ dependencies:
197
197
  version: '0'
198
198
  type: :runtime
199
199
  prerelease: false
200
- version_requirements: *13962300
200
+ version_requirements: *15156560
201
201
  - !ruby/object:Gem::Dependency
202
202
  name: addressable
203
- requirement: &13960940 !ruby/object:Gem::Requirement
203
+ requirement: &15155700 !ruby/object:Gem::Requirement
204
204
  none: false
205
205
  requirements:
206
206
  - - ! '>='
@@ -208,7 +208,7 @@ dependencies:
208
208
  version: '0'
209
209
  type: :runtime
210
210
  prerelease: false
211
- version_requirements: *13960940
211
+ version_requirements: *15155700
212
212
  description: Parse EPUB 3 book loosely
213
213
  email:
214
214
  - KitaitiMakoto@gmail.com
@@ -219,6 +219,7 @@ extra_rdoc_files: []
219
219
  files:
220
220
  - .gemtest
221
221
  - .gitignore
222
+ - .gitmodules
222
223
  - Gemfile
223
224
  - MIT-LICENSE
224
225
  - README.markdown
@@ -255,6 +256,8 @@ files:
255
256
  - schemas/epub-xhtml-30.sch
256
257
  - schemas/ocf-container-30.rnc
257
258
  - test/fixtures/book/META-INF/container.xml
259
+ - test/fixtures/book/OPS/CASE-SENSITIVE.xhtml
260
+ - test/fixtures/book/OPS/case-sensitive.xhtml
258
261
  - test/fixtures/book/OPS/nav.xhtml
259
262
  - test/fixtures/book/mimetype
260
263
  - test/helper.rb
@@ -263,7 +266,21 @@ files:
263
266
  - test/test_parser_content_document.rb
264
267
  - test/test_parser_ocf.rb
265
268
  - test/test_parser_publication.rb
269
+ - test/test_publication.rb
266
270
  - test/fixtures/book/OPS/ルートファイル.opf
271
+ - doc/method_list.html
272
+ - doc/EPUB.html
273
+ - doc/file.README.html
274
+ - doc/file.Item.html
275
+ - doc/index.html
276
+ - doc/AcceptHashAndYieldSlef.html
277
+ - doc/file.Home.html
278
+ - doc/_index.html
279
+ - doc/file_list.html
280
+ - doc/AcceptHashAndYieldSelf.html
281
+ - doc/frames.html
282
+ - doc/class_list.html
283
+ - doc/top-level-namespace.html
267
284
  homepage: https://github.com/KitaitiMakoto/epub-parser
268
285
  licenses:
269
286
  - MIT
@@ -279,7 +296,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
279
296
  version: '0'
280
297
  segments:
281
298
  - 0
282
- hash: -473258669036225186
299
+ hash: 2655157139786111314
283
300
  required_rubygems_version: !ruby/object:Gem::Requirement
284
301
  none: false
285
302
  requirements:
@@ -288,7 +305,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
288
305
  version: '0'
289
306
  segments:
290
307
  - 0
291
- hash: -473258669036225186
308
+ hash: 2655157139786111314
292
309
  requirements: []
293
310
  rubyforge_project:
294
311
  rubygems_version: 1.8.8