epuber 0.3.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 (206) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +6 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +46 -0
  5. data/bin/epuber +10 -0
  6. data/epuber.gemspec +51 -0
  7. data/lib/epuber.rb +14 -0
  8. data/lib/epuber/book.rb +267 -0
  9. data/lib/epuber/book/contributor.rb +90 -0
  10. data/lib/epuber/book/file_request.rb +68 -0
  11. data/lib/epuber/book/target.rb +284 -0
  12. data/lib/epuber/book/toc_item.rb +130 -0
  13. data/lib/epuber/checker.rb +19 -0
  14. data/lib/epuber/checker/text_checker.rb +129 -0
  15. data/lib/epuber/checker_transformer_base.rb +71 -0
  16. data/lib/epuber/command.rb +65 -0
  17. data/lib/epuber/command/compile.rb +142 -0
  18. data/lib/epuber/command/init.rb +145 -0
  19. data/lib/epuber/command/server.rb +59 -0
  20. data/lib/epuber/compiler.rb +255 -0
  21. data/lib/epuber/compiler/compilation_context.rb +86 -0
  22. data/lib/epuber/compiler/file_finders/abstract.rb +270 -0
  23. data/lib/epuber/compiler/file_finders/imaginary.rb +167 -0
  24. data/lib/epuber/compiler/file_finders/normal.rb +22 -0
  25. data/lib/epuber/compiler/file_resolver.rb +316 -0
  26. data/lib/epuber/compiler/file_types/abstract_file.rb +119 -0
  27. data/lib/epuber/compiler/file_types/bade_file.rb +39 -0
  28. data/lib/epuber/compiler/file_types/container_xml_file.rb +26 -0
  29. data/lib/epuber/compiler/file_types/generated_file.rb +29 -0
  30. data/lib/epuber/compiler/file_types/ibooks_display_options_file.rb +31 -0
  31. data/lib/epuber/compiler/file_types/image_file.rb +42 -0
  32. data/lib/epuber/compiler/file_types/mime_type_file.rb +20 -0
  33. data/lib/epuber/compiler/file_types/nav_file.rb +42 -0
  34. data/lib/epuber/compiler/file_types/opf_file.rb +27 -0
  35. data/lib/epuber/compiler/file_types/source_file.rb +52 -0
  36. data/lib/epuber/compiler/file_types/static_file.rb +18 -0
  37. data/lib/epuber/compiler/file_types/stylus_file.rb +20 -0
  38. data/lib/epuber/compiler/file_types/xhtml_file.rb +102 -0
  39. data/lib/epuber/compiler/generator.rb +67 -0
  40. data/lib/epuber/compiler/meta_inf_generator.rb +41 -0
  41. data/lib/epuber/compiler/nav_generator.rb +201 -0
  42. data/lib/epuber/compiler/opf_generator.rb +284 -0
  43. data/lib/epuber/compiler/xhtml_processor.rb +254 -0
  44. data/lib/epuber/config.rb +133 -0
  45. data/lib/epuber/dsl/attribute.rb +248 -0
  46. data/lib/epuber/dsl/attribute_support.rb +130 -0
  47. data/lib/epuber/dsl/object.rb +145 -0
  48. data/lib/epuber/dsl/tree_object.rb +101 -0
  49. data/lib/epuber/helper.rb +19 -0
  50. data/lib/epuber/lockfile.rb +55 -0
  51. data/lib/epuber/plugin.rb +108 -0
  52. data/lib/epuber/ruby_extensions/match_data.rb +40 -0
  53. data/lib/epuber/ruby_extensions/thread.rb +13 -0
  54. data/lib/epuber/server.rb +614 -0
  55. data/lib/epuber/server/auto_refresh/auto_refresh.coffee +97 -0
  56. data/lib/epuber/server/auto_refresh/connector.coffee +125 -0
  57. data/lib/epuber/server/auto_refresh/protocol.coffee +41 -0
  58. data/lib/epuber/server/auto_refresh/reloader.coffee +261 -0
  59. data/lib/epuber/server/base.styl +3 -0
  60. data/lib/epuber/server/basic.styl +211 -0
  61. data/lib/epuber/server/book_content.styl +39 -0
  62. data/lib/epuber/server/default_cover.png +0 -0
  63. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Bold.ttf +0 -0
  64. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-BoldItalic.ttf +0 -0
  65. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Italic.ttf +0 -0
  66. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Regular.ttf +0 -0
  67. data/lib/epuber/server/handlers.rb +67 -0
  68. data/lib/epuber/server/keyboard_control.coffee +6 -0
  69. data/lib/epuber/server/pages/book.bade +75 -0
  70. data/lib/epuber/server/pages/common.bade +59 -0
  71. data/lib/epuber/server/pages/files.bade +17 -0
  72. data/lib/epuber/server/pages/toc.bade +29 -0
  73. data/lib/epuber/server/support.coffee +10 -0
  74. data/lib/epuber/templates/template.bookspec +143 -0
  75. data/lib/epuber/third_party/bower.rb +22 -0
  76. data/lib/epuber/third_party/bower/bower.json +10 -0
  77. data/lib/epuber/third_party/bower/bower_components/cookies-js/bower.json +10 -0
  78. data/lib/epuber/third_party/bower/bower_components/cookies-js/dist/cookies.d.ts +33 -0
  79. data/lib/epuber/third_party/bower/bower_components/cookies-js/dist/cookies.js +173 -0
  80. data/lib/epuber/third_party/bower/bower_components/cookies-js/dist/cookies.min.js +6 -0
  81. data/lib/epuber/third_party/bower/bower_components/jquery/MIT-LICENSE.txt +21 -0
  82. data/lib/epuber/third_party/bower/bower_components/jquery/bower.json +28 -0
  83. data/lib/epuber/third_party/bower/bower_components/jquery/dist/jquery.js +9210 -0
  84. data/lib/epuber/third_party/bower/bower_components/jquery/dist/jquery.min.js +5 -0
  85. data/lib/epuber/third_party/bower/bower_components/jquery/dist/jquery.min.map +1 -0
  86. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax.js +786 -0
  87. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/jsonp.js +89 -0
  88. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/load.js +75 -0
  89. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/parseJSON.js +13 -0
  90. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/parseXML.js +28 -0
  91. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/script.js +64 -0
  92. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/var/nonce.js +5 -0
  93. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/var/rquery.js +3 -0
  94. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/xhr.js +136 -0
  95. data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes.js +11 -0
  96. data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/attr.js +141 -0
  97. data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/classes.js +158 -0
  98. data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/prop.js +94 -0
  99. data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/support.js +35 -0
  100. data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/val.js +161 -0
  101. data/lib/epuber/third_party/bower/bower_components/jquery/src/callbacks.js +205 -0
  102. data/lib/epuber/third_party/bower/bower_components/jquery/src/core.js +502 -0
  103. data/lib/epuber/third_party/bower/bower_components/jquery/src/core/access.js +60 -0
  104. data/lib/epuber/third_party/bower/bower_components/jquery/src/core/init.js +123 -0
  105. data/lib/epuber/third_party/bower/bower_components/jquery/src/core/parseHTML.js +39 -0
  106. data/lib/epuber/third_party/bower/bower_components/jquery/src/core/ready.js +97 -0
  107. data/lib/epuber/third_party/bower/bower_components/jquery/src/core/var/rsingleTag.js +4 -0
  108. data/lib/epuber/third_party/bower/bower_components/jquery/src/css.js +450 -0
  109. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/addGetHookIf.js +22 -0
  110. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/curCSS.js +57 -0
  111. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/defaultDisplay.js +70 -0
  112. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/hiddenVisibleSelectors.js +15 -0
  113. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/support.js +96 -0
  114. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/swap.js +28 -0
  115. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/cssExpand.js +3 -0
  116. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/getStyles.js +12 -0
  117. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/isHidden.js +13 -0
  118. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/rmargin.js +3 -0
  119. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/rnumnonpx.js +5 -0
  120. data/lib/epuber/third_party/bower/bower_components/jquery/src/data.js +178 -0
  121. data/lib/epuber/third_party/bower/bower_components/jquery/src/data/Data.js +181 -0
  122. data/lib/epuber/third_party/bower/bower_components/jquery/src/data/accepts.js +20 -0
  123. data/lib/epuber/third_party/bower/bower_components/jquery/src/data/var/data_priv.js +5 -0
  124. data/lib/epuber/third_party/bower/bower_components/jquery/src/data/var/data_user.js +5 -0
  125. data/lib/epuber/third_party/bower/bower_components/jquery/src/deferred.js +149 -0
  126. data/lib/epuber/third_party/bower/bower_components/jquery/src/deprecated.js +13 -0
  127. data/lib/epuber/third_party/bower/bower_components/jquery/src/dimensions.js +50 -0
  128. data/lib/epuber/third_party/bower/bower_components/jquery/src/effects.js +648 -0
  129. data/lib/epuber/third_party/bower/bower_components/jquery/src/effects/Tween.js +114 -0
  130. data/lib/epuber/third_party/bower/bower_components/jquery/src/effects/animatedSelector.js +13 -0
  131. data/lib/epuber/third_party/bower/bower_components/jquery/src/event.js +868 -0
  132. data/lib/epuber/third_party/bower/bower_components/jquery/src/event/ajax.js +13 -0
  133. data/lib/epuber/third_party/bower/bower_components/jquery/src/event/alias.js +39 -0
  134. data/lib/epuber/third_party/bower/bower_components/jquery/src/event/support.js +9 -0
  135. data/lib/epuber/third_party/bower/bower_components/jquery/src/exports/amd.js +24 -0
  136. data/lib/epuber/third_party/bower/bower_components/jquery/src/exports/global.js +32 -0
  137. data/lib/epuber/third_party/bower/bower_components/jquery/src/intro.js +44 -0
  138. data/lib/epuber/third_party/bower/bower_components/jquery/src/jquery.js +37 -0
  139. data/lib/epuber/third_party/bower/bower_components/jquery/src/manipulation.js +580 -0
  140. data/lib/epuber/third_party/bower/bower_components/jquery/src/manipulation/_evalUrl.js +18 -0
  141. data/lib/epuber/third_party/bower/bower_components/jquery/src/manipulation/support.js +32 -0
  142. data/lib/epuber/third_party/bower/bower_components/jquery/src/manipulation/var/rcheckableType.js +3 -0
  143. data/lib/epuber/third_party/bower/bower_components/jquery/src/offset.js +207 -0
  144. data/lib/epuber/third_party/bower/bower_components/jquery/src/outro.js +1 -0
  145. data/lib/epuber/third_party/bower/bower_components/jquery/src/queue.js +142 -0
  146. data/lib/epuber/third_party/bower/bower_components/jquery/src/queue/delay.js +22 -0
  147. data/lib/epuber/third_party/bower/bower_components/jquery/src/selector-native.js +172 -0
  148. data/lib/epuber/third_party/bower/bower_components/jquery/src/selector-sizzle.js +14 -0
  149. data/lib/epuber/third_party/bower/bower_components/jquery/src/selector.js +1 -0
  150. data/lib/epuber/third_party/bower/bower_components/jquery/src/serialize.js +111 -0
  151. data/lib/epuber/third_party/bower/bower_components/jquery/src/sizzle/dist/sizzle.js +2067 -0
  152. data/lib/epuber/third_party/bower/bower_components/jquery/src/sizzle/dist/sizzle.min.js +3 -0
  153. data/lib/epuber/third_party/bower/bower_components/jquery/src/sizzle/dist/sizzle.min.map +1 -0
  154. data/lib/epuber/third_party/bower/bower_components/jquery/src/traversing.js +199 -0
  155. data/lib/epuber/third_party/bower/bower_components/jquery/src/traversing/findFilter.js +100 -0
  156. data/lib/epuber/third_party/bower/bower_components/jquery/src/traversing/var/rneedsContext.js +6 -0
  157. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/arr.js +3 -0
  158. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/class2type.js +4 -0
  159. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/concat.js +5 -0
  160. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/hasOwn.js +5 -0
  161. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/indexOf.js +5 -0
  162. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/pnum.js +3 -0
  163. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/push.js +5 -0
  164. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/rnotwhite.js +3 -0
  165. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/slice.js +5 -0
  166. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/strundefined.js +3 -0
  167. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/support.js +4 -0
  168. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/toString.js +5 -0
  169. data/lib/epuber/third_party/bower/bower_components/jquery/src/wrap.js +79 -0
  170. data/lib/epuber/third_party/bower/bower_components/keymaster/MIT-LICENSE +20 -0
  171. data/lib/epuber/third_party/bower/bower_components/keymaster/Makefile +4 -0
  172. data/lib/epuber/third_party/bower/bower_components/keymaster/README.markdown +212 -0
  173. data/lib/epuber/third_party/bower/bower_components/keymaster/bower.json +27 -0
  174. data/lib/epuber/third_party/bower/bower_components/keymaster/keymaster.js +296 -0
  175. data/lib/epuber/third_party/bower/bower_components/keymaster/package.json +11 -0
  176. data/lib/epuber/third_party/bower/bower_components/keymaster/test.html +93 -0
  177. data/lib/epuber/third_party/bower/bower_components/spin.js/LICENSE.txt +21 -0
  178. data/lib/epuber/third_party/bower/bower_components/spin.js/README.md +21 -0
  179. data/lib/epuber/third_party/bower/bower_components/spin.js/bower.json +18 -0
  180. data/lib/epuber/third_party/bower/bower_components/spin.js/jquery.spin.js +80 -0
  181. data/lib/epuber/third_party/bower/bower_components/spin.js/spin.js +337 -0
  182. data/lib/epuber/third_party/bower/bower_components/uri.js/LICENSE.txt +21 -0
  183. data/lib/epuber/third_party/bower/bower_components/uri.js/README.md +534 -0
  184. data/lib/epuber/third_party/bower/bower_components/uri.js/bower.json +16 -0
  185. data/lib/epuber/third_party/bower/bower_components/uri.js/contributing.md +19 -0
  186. data/lib/epuber/third_party/bower/bower_components/uri.js/src/IPv6.js +188 -0
  187. data/lib/epuber/third_party/bower/bower_components/uri.js/src/SecondLevelDomains.js +241 -0
  188. data/lib/epuber/third_party/bower/bower_components/uri.js/src/URI.fragmentQuery.js +104 -0
  189. data/lib/epuber/third_party/bower/bower_components/uri.js/src/URI.fragmentURI.js +97 -0
  190. data/lib/epuber/third_party/bower/bower_components/uri.js/src/URI.js +2115 -0
  191. data/lib/epuber/third_party/bower/bower_components/uri.js/src/URI.min.js +86 -0
  192. data/lib/epuber/third_party/bower/bower_components/uri.js/src/URITemplate.js +499 -0
  193. data/lib/epuber/third_party/bower/bower_components/uri.js/src/jquery.URI.js +235 -0
  194. data/lib/epuber/third_party/bower/bower_components/uri.js/src/jquery.URI.min.js +7 -0
  195. data/lib/epuber/third_party/bower/bower_components/uri.js/src/punycode.js +508 -0
  196. data/lib/epuber/transformer.rb +19 -0
  197. data/lib/epuber/transformer/text_transformer.rb +60 -0
  198. data/lib/epuber/user_interface.rb +186 -0
  199. data/lib/epuber/vendor/globals_context.rb +26 -0
  200. data/lib/epuber/vendor/hash_binding.rb +26 -0
  201. data/lib/epuber/vendor/nokogiri_extensions.rb +30 -0
  202. data/lib/epuber/vendor/ruby_templater.rb +71 -0
  203. data/lib/epuber/vendor/size.rb +20 -0
  204. data/lib/epuber/vendor/version.rb +83 -0
  205. data/lib/epuber/version.rb +4 -0
  206. metadata +556 -0
@@ -0,0 +1,167 @@
1
+ # encoding: utf-8
2
+
3
+ require 'unicode_normalize'
4
+
5
+
6
+ module Epuber
7
+ class Compiler
8
+ module FileFinders
9
+ require_relative 'abstract'
10
+
11
+ class Imaginary < Abstract
12
+ class DirEntry
13
+ # @return [Hash<String, String | DirEntry>]
14
+ #
15
+ attr_accessor :entries
16
+
17
+ attr_reader :name
18
+
19
+ def initialize(name)
20
+ @name = name
21
+ @entries = {}
22
+ end
23
+
24
+ def [](key)
25
+ @entries[key]
26
+ end
27
+
28
+ def []=(key, value)
29
+ @entries[key] = value
30
+ end
31
+
32
+ def ==(other)
33
+ name == other.name && entries == other.entries
34
+ end
35
+ end
36
+
37
+ class FileEntry
38
+ attr_reader :name
39
+
40
+ attr_reader :absolute_path
41
+
42
+ def initialize(name, absolute_path)
43
+ @name = name
44
+ @absolute_path = absolute_path
45
+ end
46
+
47
+ def ==(other)
48
+ other.is_a?(FileEntry) ? name == other.name : name == other.to_s
49
+ end
50
+ end
51
+
52
+ # @return [DirEntry]
53
+ #
54
+ attr_reader :root
55
+
56
+ def initialize(source_path)
57
+ super
58
+ @root = DirEntry.new('/')
59
+
60
+ make_dir_p(File.expand_path(source_path))
61
+ end
62
+
63
+ # @param [String | Array<String>] path path to folder to create
64
+ #
65
+ # @return [DirEntry] dir entry for given path
66
+ #
67
+ def make_dir_p(path)
68
+ components = path.is_a?(Array) ? path : self.class.path_parts(path)
69
+
70
+ current = root
71
+ components.each do |dir|
72
+ entry = current[dir]
73
+ current[dir] = entry = DirEntry.new(dir) if entry.nil?
74
+ current = entry
75
+ end
76
+
77
+ current
78
+ end
79
+
80
+ # @param
81
+ def add_file(file_path)
82
+ file_path = File.expand_path(file_path, source_path)
83
+
84
+ *path, file_name = self.class.path_parts(file_path)
85
+
86
+ make_dir_p(path)[file_name] = FileEntry.new(file_name, file_path)
87
+ end
88
+
89
+
90
+ def __core_find_files_from_pattern(pattern)
91
+ parts = self.class.path_parts(pattern)
92
+ find_recurser(root, parts).flatten.map do |item|
93
+ item.absolute_path
94
+ end
95
+ end
96
+
97
+ def __core_file?(path)
98
+ components = self.class.path_parts(path)
99
+
100
+ current = root
101
+ components.each do |dir|
102
+ current = current.respond_to?(:[]) ? current[dir] : nil
103
+ end
104
+
105
+ current.is_a?(FileEntry)
106
+ end
107
+
108
+ private
109
+
110
+ def self.path_parts(path)
111
+ path.split(File::SEPARATOR).reject(&:empty?)
112
+ end
113
+
114
+ def find_recurser(dir, parts)
115
+ return [] unless dir.respond_to? :[]
116
+
117
+ pattern, *parts = parts
118
+ matches = case pattern
119
+ when '**'
120
+ case parts
121
+ when ['*']
122
+ parts = [] # end recursion
123
+ directories_under(dir).map do |d|
124
+ d.entries.select do |f|
125
+ (f.is_a?(FileEntry) || f.is_a?(DirEntry)) &&
126
+ f.name.match(/\A(?!\.)/)
127
+ end
128
+ end.flatten.uniq
129
+ when []
130
+ parts = [] # end recursion
131
+ dir.entries.flatten.uniq
132
+ else
133
+ directories_under(dir)
134
+ end
135
+ else
136
+ regex_body = pattern.gsub('.', '\.')
137
+ .gsub('?', '.')
138
+ .gsub('*', '.*')
139
+ .gsub('(', '\(')
140
+ .gsub(')', '\)')
141
+ .gsub(/\{(.*?)\}/) do
142
+ "(#{Regexp.last_match[1].gsub(',', '|')})"
143
+ end
144
+ .gsub(/\A\./, '(?!\.).')
145
+ dir.entries.reject { |k, _v| /\A#{regex_body}\Z/ !~ k }.values
146
+ end
147
+
148
+ if parts.empty? # we're done recursing
149
+ matches
150
+ else
151
+ matches.map { |entry| find_recurser(entry, parts) }
152
+ end
153
+ end
154
+
155
+ # @param [DirEntry] dir
156
+ #
157
+ # @return [Hash<String, DirEntry>]
158
+ #
159
+ def directories_under(dir)
160
+ children = dir.entries.values.select { |f| f.is_a?(DirEntry) }
161
+ (Array(dir) + children + children.map { |c| directories_under(c) }).flatten.uniq
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ require 'unicode_normalize'
4
+
5
+
6
+ module Epuber
7
+ class Compiler
8
+ module FileFinders
9
+ require_relative 'abstract'
10
+
11
+ class Normal < Abstract
12
+ def __core_find_files_from_pattern(pattern)
13
+ Dir.glob(pattern)
14
+ end
15
+
16
+ def __core_file?(path)
17
+ File.file?(path)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,316 @@
1
+ # encoding: utf-8
2
+
3
+ require 'unicode_normalize'
4
+
5
+
6
+
7
+ module Epuber
8
+ class Compiler
9
+ require_relative 'file_finders/normal'
10
+ require_relative 'file_finders/imaginary'
11
+
12
+ require_relative 'file_types/abstract_file'
13
+ require_relative 'file_types/generated_file'
14
+ require_relative 'file_types/static_file'
15
+ require_relative 'file_types/stylus_file'
16
+ require_relative 'file_types/xhtml_file'
17
+ require_relative 'file_types/bade_file'
18
+ require_relative 'file_types/image_file'
19
+ require_relative 'file_types/nav_file'
20
+ require_relative 'file_types/opf_file'
21
+ require_relative 'file_types/mime_type_file'
22
+ require_relative 'file_types/container_xml_file'
23
+ require_relative 'file_types/ibooks_display_options_file'
24
+
25
+
26
+ class FileResolver
27
+ class ResolveError < StandardError; end
28
+
29
+ PATH_TYPES = [:spine, :manifest, :package, nil]
30
+
31
+ # @return [String] path where should look for source files
32
+ #
33
+ attr_reader :source_path
34
+
35
+ # @return [String] path where will be stored result files
36
+ #
37
+ attr_reader :destination_path
38
+
39
+
40
+ # @return [Array<FileTypes::Abstract>] all files that will be in spine
41
+ #
42
+ attr_reader :spine_files
43
+
44
+ # @return [Array<FileTypes::Abstract>] all files that has to be in manifest file (OPF)
45
+ #
46
+ attr_reader :manifest_files
47
+
48
+ # @return [Array<FileTypes::Abstract>] all files that will be copied to EPUB package
49
+ #
50
+ attr_reader :package_files
51
+
52
+ # @return [Array<FileTypes::Abstract>] totally all files
53
+ #
54
+ attr_reader :files
55
+
56
+
57
+ # @return [FileFinders::Normal]
58
+ #
59
+ attr_reader :source_finder
60
+
61
+ # @return [FileFinders::Imaginary]
62
+ #
63
+ attr_reader :dest_finder
64
+
65
+
66
+ # @param [String] source_path
67
+ # @param [String] destination_path
68
+ #
69
+ def initialize(source_path, destination_path)
70
+ @source_finder = FileFinders::Normal.new(source_path.unicode_normalize)
71
+ @source_finder.ignored_patterns << ::File.join(Config::WORKING_PATH, '**')
72
+
73
+ @dest_finder = FileFinders::Imaginary.new(destination_path.unicode_normalize)
74
+
75
+ @source_path = source_path.unicode_normalize
76
+ @destination_path = destination_path.unicode_normalize
77
+
78
+ @spine_files = []
79
+ @manifest_files = []
80
+ @package_files = []
81
+ @files = []
82
+
83
+ @request_to_files = Hash.new { |hash, key| hash[key] = [] }
84
+ @final_destination_path_to_file = {}
85
+ @source_path_to_file = {}
86
+ @abs_source_path_to_file = {}
87
+ end
88
+
89
+ # @param [Epuber::Book::FileRequest] file_request
90
+ #
91
+ def add_file_from_request(file_request, path_type = :manifest)
92
+ if file_request.only_one
93
+ file_path = @source_finder.find_file(file_request.source_pattern, groups: file_request.group)
94
+ file_class = self.class.file_class_for(File.extname(file_path))
95
+
96
+ file = file_class.new(file_path)
97
+ file.file_request = file_request
98
+ file.path_type = path_type
99
+
100
+ add_file(file)
101
+ else
102
+ file_paths = @source_finder.find_all(file_request.source_pattern, groups: file_request.group)
103
+ file_paths.map do |path|
104
+ file_class = self.class.file_class_for(File.extname(path))
105
+
106
+ file = file_class.new(path)
107
+ file.file_request = file_request
108
+ file.path_type = path_type
109
+
110
+ add_file(file)
111
+ end
112
+ end
113
+ end
114
+
115
+ # @param [Epuber::Compiler::FileTypes::AbstractFile] file
116
+ #
117
+ def add_file(file)
118
+ type = file.path_type
119
+
120
+ unless PATH_TYPES.include?(type)
121
+ raise "Unknown file.path_type #{type.inspect}, expected are :spine, :manifest, :package or nil"
122
+ end
123
+
124
+ resolve_destination_path(file)
125
+
126
+ existing_file = @final_destination_path_to_file[file.final_destination_path]
127
+
128
+ # save mapping from file_request to file, file_request can be different, but result file could be the same ...
129
+ unless file.try(:file_request).nil?
130
+ @request_to_files[file.file_request] << (existing_file || file)
131
+ end
132
+
133
+ # return existing file if already exists, new file will be thrown away
134
+ return existing_file unless existing_file.nil?
135
+
136
+ if [:spine].include?(type)
137
+ @spine_files << file
138
+ end
139
+
140
+ if [:spine, :manifest].include?(type)
141
+ @manifest_files << file
142
+ end
143
+
144
+ if [:spine, :manifest, :package].include?(type)
145
+ @package_files << file
146
+ end
147
+
148
+ @files << file
149
+
150
+
151
+ dest_finder.add_file(file.destination_path)
152
+
153
+ @final_destination_path_to_file[file.final_destination_path] = file
154
+
155
+ if file.respond_to?(:source_path) && !file.source_path.nil?
156
+ @source_path_to_file[file.source_path] = file
157
+ end
158
+
159
+ if file.respond_to?(:abs_source_path) && !file.abs_source_path.nil?
160
+ @abs_source_path_to_file[file.abs_source_path] = file
161
+ end
162
+ end
163
+
164
+ # Get instance of file from request instance
165
+ #
166
+ # @param [Book::FileRequest] file_request
167
+ #
168
+ # @return [FileTypes::AbstractFile, Array<FileTypes::AbstractFile>]
169
+ #
170
+ def file_from_request(file_request)
171
+ files = @request_to_files[file_request]
172
+
173
+ if files.empty? && file_request.only_one
174
+ begin
175
+ path = @source_finder.find_file(file_request.source_pattern, groups: file_request.group)
176
+ file = file_with_source_path(path)
177
+
178
+ unless file.nil?
179
+ @request_to_files[file_request] = file
180
+ files = [file]
181
+ end
182
+ rescue FileFinders::FileNotFoundError, FileFinders::MultipleFilesFoundError
183
+ # noop
184
+ end
185
+ end
186
+
187
+ if file_request.only_one
188
+ files.first # @request_to_files always returns array, see #initialize method
189
+ else
190
+ files
191
+ end
192
+ end
193
+
194
+ # Get instance of file from source path, but this is relative path from project root, if you want to find
195
+ # file with absolute source path see #file_with_abs_source_path
196
+ #
197
+ # @param [String] source_path
198
+ #
199
+ # @return [FileTypes::AbstractFile]
200
+ #
201
+ def file_with_source_path(source_path)
202
+ source_path = source_path.unicode_normalize
203
+ @source_path_to_file[source_path] || @abs_source_path_to_file[source_path]
204
+ end
205
+
206
+ # Method to get instance of file on specific path
207
+ #
208
+ # @param [String] path path to file from destination folder
209
+ # @param [String] path_type path type of path (:spine, :manifest or :package)
210
+ #
211
+ # @return [FileTypes::AbstractFile]
212
+ #
213
+ def file_with_destination_path(path, path_type = :manifest)
214
+ final_path = File.join(*self.class.path_comps_for(destination_path, path_type), path.unicode_normalize)
215
+ @final_destination_path_to_file[final_path]
216
+ end
217
+
218
+ # Method to find all files that should be deleted, because they are not in files in receiver
219
+ #
220
+ # @return [Array<String>] list of files that should be deleted in destination directory
221
+ #
222
+ def unneeded_files_in_destination
223
+ requested_paths = files.map do |file|
224
+ file.pkg_destination_path
225
+ end
226
+
227
+ existing_paths = FileFinders::Normal.new(destination_path).find_all('*')
228
+
229
+ unnecessary_paths = existing_paths - requested_paths
230
+
231
+ unnecessary_paths.select! do |path|
232
+ !::File.directory?(File.join(destination_path, path))
233
+ end
234
+
235
+ unnecessary_paths
236
+ end
237
+
238
+
239
+ ##################################################################################################################
240
+
241
+ private
242
+
243
+ # @param [String] path path to some file
244
+ #
245
+ # @return [String] path with changed extension
246
+ #
247
+ def renamed_file_with_path(path)
248
+ extname = File.extname(path)
249
+ new_extname = FileFinders::EXTENSIONS_RENAME[extname]
250
+
251
+ if new_extname.nil?
252
+ path
253
+ else
254
+ path.sub(/#{Regexp.escape(extname)}$/, new_extname)
255
+ end
256
+ end
257
+
258
+ # @param file [Epuber::Compiler::AbstractFile]
259
+ #
260
+ # @return [nil]
261
+ #
262
+ def resolve_destination_path(file)
263
+ if file.final_destination_path.nil?
264
+ dest_path = if file.respond_to?(:source_path) && !file.source_path.nil?
265
+ file.abs_source_path = File.expand_path(file.source_path, source_path)
266
+ renamed_file_with_path(file.source_path)
267
+ elsif !file.destination_path.nil?
268
+ file.destination_path
269
+ else
270
+ raise ResolveError, "What should I do with file that doesn't have source path or destination path? file: #{file.inspect}"
271
+ end
272
+
273
+ file.destination_path = dest_path
274
+ file.pkg_destination_path = File.join(*self.class.path_comps_for(file.path_type), dest_path)
275
+ file.final_destination_path = File.join(destination_path, file.pkg_destination_path)
276
+ end
277
+ end
278
+
279
+ # @param [String] extname extension of file
280
+ #
281
+ # @return [Class]
282
+ #
283
+ def self.file_class_for(extname)
284
+ mapping = {
285
+ '.styl' => FileTypes::StylusFile,
286
+
287
+ '.bade' => FileTypes::BadeFile,
288
+ '.xhtml' => FileTypes::XHTMLFile,
289
+ '.html' => FileTypes::XHTMLFile,
290
+
291
+ '.jpg' => FileTypes::ImageFile,
292
+ '.jpeg' => FileTypes::ImageFile,
293
+ '.png' => FileTypes::ImageFile,
294
+ }
295
+
296
+ mapping[extname] || FileTypes::StaticFile
297
+ end
298
+
299
+ # @param [String] root_path path to root of the package
300
+ # @param [Symbol] path_type path type of file
301
+ #
302
+ # @return [Array<String>] path components
303
+ #
304
+ def self.path_comps_for(root_path = nil, path_type)
305
+ case path_type
306
+ when :spine, :manifest
307
+ Array(root_path) + [Compiler::EPUB_CONTENT_FOLDER]
308
+ when :package
309
+ Array(root_path)
310
+ else
311
+ nil
312
+ end
313
+ end
314
+ end
315
+ end
316
+ end