Class: Bookbinder::Package
- Inherits:
-
Object
- Object
- Bookbinder::Package
- Defined in:
- lib/bookbinder/package.rb
Direct Known Subclasses
Defined Under Namespace
Classes: EPUB, MP3Audiobook, MediaRipper, Openbook
Instance Attribute Summary collapse
-
#content_root ⇒ Object
Returns the value of attribute content_root.
-
#file_aliases ⇒ Object
Returns the value of attribute file_aliases.
-
#file_system ⇒ Object
Returns the value of attribute file_system.
-
#map ⇒ Object
Returns the value of attribute map.
-
#options ⇒ Object
Returns the value of attribute options.
-
#warnings ⇒ Object
readonly
Returns the value of attribute warnings.
Class Method Summary collapse
-
.build(path) ⇒ Object
Creates a new package of this class pointing at the given path (but not reading from it automatically).
-
.read(path) ⇒ Object
Creates a new package of this class by reading content from a path.
-
.recognize(path) ⇒ Object
In subclasses, return true if you can handle the path.
-
.require_transforms(dir) ⇒ Object
This will require() all the .rb files within the given subdirectory of ‘bookbinder/transform’.
- .transforms ⇒ Object
Instance Method Summary collapse
- #all_book_content ⇒ Object
-
#apply_transform(mthd, transform_class) ⇒ Object
Applies the given transform by instantiating the class and invoking the specified method on it.
-
#build(path) ⇒ Object
Prepares this package for mapping the contents of the given path.
-
#copy_to(path_or_file_system, content_root) ⇒ Object
Copy all components and resources in the map to the new file system, then creates a new temporary package based on this one and yields it.
-
#export(package_class) ⇒ Object
Creates a new package of the given class, using our map and file_system, and returns it.
-
#file(path, root_path = @content_root) ⇒ Object
Returns a file object for the given path within this package – by default, the path is from this package’s content_root.
-
#file_path(path, root_path = @content_root) ⇒ Object
Returns the fully-resolved path to a file within this package, converting aliases and applying the content_root if appropriate.
-
#from_map ⇒ Object
This is the default “from_map” behavior, but feel free to override it in subclasses.
-
#if_file(*file_args) {|f| ... } ⇒ Object
Yields the file only if it exists.
-
#import(map, file_system, content_root, options) ⇒ Object
Copies state: a map, a file-system, and a content root.
-
#initialize ⇒ Package
constructor
A new instance of Package.
-
#read(path) ⇒ Object
Reads the path and generates a hash “map” of the book, returning it.
- #reset_transforms ⇒ Object
-
#save_open_files ⇒ Object
Any file that is marked ‘dirty’ (because it has been opened in ‘w’ mode) will be written out to its file-system.
-
#to_map ⇒ Object
This is the default “to_map” behavior, but feel free to override it in subclasses.
-
#transforms ⇒ Object
The list of transforms to be applied when mapping or writing this package.
- #warn(msg) ⇒ Object
-
#write(path) ⇒ Object
Writes package to path.
Constructor Details
#initialize ⇒ Package
Returns a new instance of Package.
57 58 59 60 61 62 63 |
# File 'lib/bookbinder/package.rb', line 57 def initialize @content_root = '' @file_aliases = {} @options = {} @files = {} reset_transforms end |
Instance Attribute Details
#content_root ⇒ Object
Returns the value of attribute content_root.
3 4 5 |
# File 'lib/bookbinder/package.rb', line 3 def content_root @content_root end |
#file_aliases ⇒ Object
Returns the value of attribute file_aliases.
3 4 5 |
# File 'lib/bookbinder/package.rb', line 3 def file_aliases @file_aliases end |
#file_system ⇒ Object
Returns the value of attribute file_system.
3 4 5 |
# File 'lib/bookbinder/package.rb', line 3 def file_system @file_system end |
#map ⇒ Object
Returns the value of attribute map.
3 4 5 |
# File 'lib/bookbinder/package.rb', line 3 def map @map end |
#options ⇒ Object
Returns the value of attribute options.
3 4 5 |
# File 'lib/bookbinder/package.rb', line 3 def @options end |
#warnings ⇒ Object (readonly)
Returns the value of attribute warnings.
4 5 6 |
# File 'lib/bookbinder/package.rb', line 4 def warnings @warnings end |
Class Method Details
.build(path) ⇒ Object
Creates a new package of this class pointing at the given path (but not reading from it automatically).
40 41 42 43 44 |
# File 'lib/bookbinder/package.rb', line 40 def self.build(path) new.tap { |pkg| pkg.build(path) } end |
.read(path) ⇒ Object
Creates a new package of this class by reading content from a path.
50 51 52 53 54 |
# File 'lib/bookbinder/package.rb', line 50 def self.read(path) new.tap { |pkg| pkg.read(path) } end |
.recognize(path) ⇒ Object
In subclasses, return true if you can handle the path. We’ll iterate through all the descendent classes of Package and return the first matching class.
11 12 13 |
# File 'lib/bookbinder/package.rb', line 11 def self.recognize(path) # IMPLEMENT IN SUBCLASSES end |
.require_transforms(dir) ⇒ Object
This will require() all the .rb files within the given subdirectory of ‘bookbinder/transform’. So, for the EPUB package, you’d just call:
require_transforms('epub')
… to load all the EPUB-specific transforms.
23 24 25 26 27 28 29 |
# File 'lib/bookbinder/package.rb', line 23 def self.require_transforms(dir) Dir.glob( File.join(File.dirname(__FILE__), 'transform', dir, '*.rb') ).each { |rb| require("bookbinder/transform/#{dir}/#{File.basename(rb, '.rb')}") } end |
.transforms ⇒ Object
32 33 34 |
# File 'lib/bookbinder/package.rb', line 32 def self.transforms [] # Implement in subclasses end |
Instance Method Details
#all_book_content ⇒ Object
133 134 135 136 137 138 139 |
# File 'lib/bookbinder/package.rb', line 133 def all_book_content book_content = [] book_content += map['cover'].values if map['cover'] book_content += map['spine'] if map['spine'] book_content += map['resources'] if map['resources'] book_content end |
#apply_transform(mthd, transform_class) ⇒ Object
Applies the given transform by instantiating the class and invoking the specified method on it. ‘mthd` should be either `to_map` or `from_map`.
Runs all dependencies (that have not already run) first.
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/bookbinder/package.rb', line 226 def apply_transform(mthd, transform_class) run = @transformed[mthd] ||= [] return if run.include?(transform_class) run.push(transform_class) transform = transform_class.new transform.dependencies.each { |dep| apply_transform(mthd, dep) } if transform.respond_to?(mthd) # puts("[TRANSFORM] #{transform_class}##{mthd}") @transform = transform @transform_method = mthd @transform.send(mthd, self) @transform = nil @transform_method = nil end end |
#build(path) ⇒ Object
Prepares this package for mapping the contents of the given path.
69 70 71 72 |
# File 'lib/bookbinder/package.rb', line 69 def build(path) @map = {} @file_system = file_system_from_path(path) end |
#copy_to(path_or_file_system, content_root) ⇒ Object
Copy all components and resources in the map to the new file system, then creates a new temporary package based on this one and yields it.
We create a new temporary package rather than using the current one so that we can have a different file system (and a different content root if we want that, and fresh hashes for ‘files`, `file_aliases`, etc).
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/bookbinder/package.rb', line 113 def copy_to(path_or_file_system, content_root) dest_file_system = path_or_file_system if path_or_file_system.kind_of?(String) dest_file_system = file_system_from_path(dest_file_system) end all_book_content.each { |ref| rsrc = file(ref['path']) dest_path = ref['path'] if content_root && !content_root.empty? dest_path = File.join(content_root, dest_path) dest_path = File.(dest_path, '/')[1..-1] end rsrc.copy_to(dest_file_system, dest_path) } self.class.new.tap { |pkg| pkg.import(@map, dest_file_system, content_root, @options) } end |
#export(package_class) ⇒ Object
Creates a new package of the given class, using our map and file_system, and returns it.
88 89 90 |
# File 'lib/bookbinder/package.rb', line 88 def export(package_class) package_class.new.import(map, file_system, content_root, ) end |
#file(path, root_path = @content_root) ⇒ Object
Returns a file object for the given path within this package – by default, the path is from this package’s content_root.
160 161 162 163 164 165 166 |
# File 'lib/bookbinder/package.rb', line 160 def file(path, root_path = @content_root) if full_path = file_path(path, root_path) @files[full_path] ||= Bookbinder::File.new(full_path, @file_system) else nil end end |
#file_path(path, root_path = @content_root) ⇒ Object
Returns the fully-resolved path to a file within this package, converting aliases and applying the content_root if appropriate.
172 173 174 175 176 177 178 179 180 181 |
# File 'lib/bookbinder/package.rb', line 172 def file_path(path, root_path = @content_root) path = file_aliases[path] if file_aliases[path] if path.kind_of?(Symbol) nil else path = File.join(root_path, path) if root_path && !root_path.empty? path = File.(path, '/')[1..-1] path end end |
#from_map ⇒ Object
This is the default “from_map” behavior, but feel free to override it in subclasses.
213 214 215 216 217 |
# File 'lib/bookbinder/package.rb', line 213 def from_map transforms.each { |transform_class| apply_transform(:from_map, transform_class) } end |
#if_file(*file_args) {|f| ... } ⇒ Object
Yields the file only if it exists.
186 187 188 189 |
# File 'lib/bookbinder/package.rb', line 186 def if_file(*file_args) f = file(*file_args) yield(f) if f && f.exists? end |
#import(map, file_system, content_root, options) ⇒ Object
Copies state: a map, a file-system, and a content root. That should be enough to be a fully independent package.
96 97 98 99 100 101 102 |
# File 'lib/bookbinder/package.rb', line 96 def import(map, file_system, content_root, ) @map = duplicate_map(map) @file_system = file_system @content_root = content_root @options = .clone self end |
#read(path) ⇒ Object
Reads the path and generates a hash “map” of the book, returning it.
78 79 80 81 82 |
# File 'lib/bookbinder/package.rb', line 78 def read(path) build(path) to_map @map end |
#reset_transforms ⇒ Object
243 244 245 246 |
# File 'lib/bookbinder/package.rb', line 243 def reset_transforms @warnings = [] @transformed = {} end |
#save_open_files ⇒ Object
Any file that is marked ‘dirty’ (because it has been opened in ‘w’ mode) will be written out to its file-system.
262 263 264 |
# File 'lib/bookbinder/package.rb', line 262 def save_open_files @files.each_value { |file| file.save } end |
#to_map ⇒ Object
This is the default “to_map” behavior, but feel free to override it in subclasses.
203 204 205 206 207 |
# File 'lib/bookbinder/package.rb', line 203 def to_map transforms.each { |transform_class| apply_transform(:to_map, transform_class) } end |
#transforms ⇒ Object
The list of transforms to be applied when mapping or writing this package.
195 196 197 |
# File 'lib/bookbinder/package.rb', line 195 def transforms self.class.transforms end |
#warn(msg) ⇒ Object
249 250 251 252 253 254 255 256 |
# File 'lib/bookbinder/package.rb', line 249 def warn(msg) @warnings.push({ :transform => @transform.class, :method => @transform_method, :message => msg }) nil end |
#write(path) ⇒ Object
Writes package to path. This is destructive! Anything already at the path will be replaced.
145 146 147 148 149 150 151 152 153 154 |
# File 'lib/bookbinder/package.rb', line 145 def write(path) tmp_path = Dir::Tmpname.create(File.basename(path)) { |tmp_path| raise Errno::EEXIST if File.exists?(tmp_path) } dest_fs = file_system_from_path(tmp_path) write_to_file_system(dest_fs) dest_fs.close if dest_fs.respond_to?(:close) FileUtils.rm_r(path) if File.exists?(path) FileUtils.move(tmp_path, path) end |