gitlab-gollum-lib 1.0.0

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,171 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'date'
4
+
5
+ #############################################################################
6
+ #
7
+ # Helper functions
8
+ #
9
+ #############################################################################
10
+
11
+ def name
12
+ @name ||= Dir['*.gemspec'].first.split('.').first
13
+ end
14
+
15
+ def version
16
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
17
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
18
+ end
19
+
20
+ # assumes x.y.z all digit version
21
+ def next_version
22
+ # x.y.z
23
+ v = version.split '.'
24
+ # bump z
25
+ v[-1] = v[-1].to_i + 1
26
+ v.join '.'
27
+ end
28
+
29
+ def bump_version
30
+ old_file = File.read("lib/#{name}.rb")
31
+ old_version_line = old_file[/^\s*VERSION\s*=\s*.*/]
32
+ new_version = next_version
33
+ # replace first match of old vesion with new version
34
+ old_file.sub!(old_version_line, " VERSION = '#{new_version}'")
35
+
36
+ File.write("lib/#{name}.rb", old_file)
37
+
38
+ new_version
39
+ end
40
+
41
+ def date
42
+ Date.today.to_s
43
+ end
44
+
45
+ def rubyforge_project
46
+ name
47
+ end
48
+
49
+ def gemspec_file
50
+ "#{name}.gemspec"
51
+ end
52
+
53
+ def gem_file
54
+ "#{name}-#{version}.gem"
55
+ end
56
+
57
+ def replace_header(head, header_name)
58
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
59
+ end
60
+
61
+ #############################################################################
62
+ #
63
+ # Standard tasks
64
+ #
65
+ #############################################################################
66
+
67
+ task :default => :test
68
+
69
+ require 'rake/testtask'
70
+ Rake::TestTask.new(:test) do |test|
71
+ test.libs << 'lib' << 'test' << '.'
72
+ test.pattern = 'test/**/test_*.rb'
73
+ test.verbose = true
74
+ end
75
+
76
+ desc "Generate RCov test coverage and open in your browser"
77
+ task :coverage do
78
+ require 'rcov'
79
+ sh "rm -fr coverage"
80
+ sh "rcov test/test_*.rb"
81
+ sh "open coverage/index.html"
82
+ end
83
+
84
+ desc "Open an irb session preloaded with this library"
85
+ task :console do
86
+ sh "irb -rubygems -r ./lib/#{name}.rb"
87
+ end
88
+
89
+ #############################################################################
90
+ #
91
+ # Custom tasks (add your own tasks here)
92
+ #
93
+ #############################################################################
94
+
95
+ desc "Update version number and gemspec"
96
+ task :bump do
97
+ puts "Updated version to #{bump_version}"
98
+ # Execute does not invoke dependencies.
99
+ # Manually invoke gemspec then validate.
100
+ Rake::Task[:gemspec].execute
101
+ Rake::Task[:validate].execute
102
+ end
103
+
104
+ #############################################################################
105
+ #
106
+ # Packaging tasks
107
+ #
108
+ #############################################################################
109
+
110
+ desc 'Create a release build'
111
+ task :release => :build do
112
+ unless `git branch` =~ /^\* master$/
113
+ puts "You must be on the master branch to release!"
114
+ exit!
115
+ end
116
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
117
+ sh "git pull"
118
+ sh "git tag v#{version}"
119
+ sh "git push origin master"
120
+ sh "git push origin v#{version}"
121
+ sh "gem push pkg/#{name}-#{version}.gem"
122
+ end
123
+
124
+ desc 'Build gem'
125
+ task :build => :gemspec do
126
+ sh "mkdir -p pkg"
127
+ sh "gem build #{gemspec_file}"
128
+ sh "mv #{gem_file} pkg"
129
+ end
130
+
131
+ desc 'Update gemspec'
132
+ task :gemspec => :validate do
133
+ # read spec file and split out manifest section
134
+ spec = File.read(gemspec_file)
135
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
136
+
137
+ # replace name version and date
138
+ replace_header(head, :name)
139
+ replace_header(head, :version)
140
+ replace_header(head, :date)
141
+ #comment this out if your rubyforge_project has a different name
142
+ replace_header(head, :rubyforge_project)
143
+
144
+ # determine file list from git ls-files
145
+ files = `git ls-files`.
146
+ split("\n").
147
+ sort.
148
+ reject { |file| file =~ /^\./ }.
149
+ reject { |file| file =~ /^(rdoc|pkg|test|Home\.md|\.gitattributes)/ }.
150
+ map { |file| " #{file}" }.
151
+ join("\n")
152
+
153
+ # piece file back together and write
154
+ manifest = " s.files = %w[\n#{files}\n ]\n"
155
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
156
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
157
+ puts "Updated #{gemspec_file}"
158
+ end
159
+
160
+ desc 'Validate lib files and version file'
161
+ task :validate do
162
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
163
+ unless libfiles.empty?
164
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
165
+ exit!
166
+ end
167
+ unless Dir['VERSION*'].empty?
168
+ puts "A `VERSION` file at root level violates Gem best practices."
169
+ exit!
170
+ end
171
+ end
@@ -0,0 +1,33 @@
1
+ Sanitization Rules
2
+ ==================
3
+
4
+ Gollum uses the [Sanitize](http://wonko.com/post/sanitize) gem for HTML
5
+ sanitization.
6
+
7
+ See `lib/gollum-lib/sanitization.rb` for actual settings.
8
+
9
+ ## ALLOWED TAGS
10
+
11
+ a, abbr, acronym, address, area, b, big, blockquote, br, button, caption,
12
+ center, cite, code, col, colgroup, dd, del, dfn, dir, div, dl, dt, em,
13
+ fieldset, font, form, h1, h2, h3, h4, h5, h6, hr, i, img, input, ins, kbd,
14
+ label, legend, li, map, menu, ol, optgroup, option, p, pre, q, s, samp,
15
+ select, small, span, strike, strong, sub, sup, table, tbody, td, textarea,
16
+ tfoot, th, thead, tr, tt, u, ul, var
17
+
18
+ ## ALLOWED ATTRIBUTES
19
+
20
+ abbr, accept, accept-charset, accesskey, action, align, alt, axis, border,
21
+ cellpadding, cellspacing, char, charoff, charset, checked, cite, class, clear,
22
+ cols, colspan, color, compact, coords, datetime, dir, disabled, enctype, for,
23
+ frame, headers, height, href, hreflang, hspace, id, ismap, label, lang,
24
+ longdesc, maxlength, media, method, multiple, name, nohref, noshade, nowrap,
25
+ prompt, readonly, rel, rev, rows, rowspan, rules, scope, selected, shape,
26
+ size, span, src, start, summary, tabindex, target, title, type, usemap,
27
+ valign, value, vspace, width
28
+
29
+ ## ALLOWED PROTOCOLS
30
+
31
+ a href: http, https, mailto, ftp, irc, apt
32
+ img src: http, https
33
+ form action: http, https
@@ -0,0 +1,75 @@
1
+ Gem::Specification.new do |s|
2
+ s.specification_version = 2 if s.respond_to? :specification_version=
3
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
+ s.rubygems_version = '0.0.1'
5
+ s.required_ruby_version = ">= 1.8.7"
6
+
7
+ s.name = 'gitlab-gollum-lib'
8
+ s.version = '1.0.0'
9
+ s.date = '2013-04-02'
10
+ s.rubyforge_project = 'gollum-lib'
11
+
12
+ s.summary = "A simple, Git-powered wiki."
13
+ s.description = "A simple, Git-powered wiki with a sweet API and local frontend."
14
+
15
+ s.authors = ["Tom Preston-Werner", "Rick Olson"]
16
+ s.email = 'tom@github.com'
17
+ s.homepage = 'http://github.com/gollum/gollum-lib'
18
+
19
+ s.require_paths = %w[lib]
20
+
21
+ s.rdoc_options = ["--charset=UTF-8"]
22
+ s.extra_rdoc_files = %w[README.md LICENSE]
23
+
24
+ s.add_dependency('gitlab-grit', '~> 2.5.1')
25
+ s.add_dependency('github-markup', ['>= 0.7.5', '< 1.0.0'])
26
+ s.add_dependency('github-markdown', '~> 0.5.3')
27
+ s.add_dependency('pygments.rb', '~> 0.4.2')
28
+ s.add_dependency('sanitize', '~> 2.0.3')
29
+ s.add_dependency('nokogiri', '~> 1.5.9')
30
+ s.add_dependency('stringex', '~> 1.5.1')
31
+
32
+ s.add_development_dependency('RedCloth', '~> 4.2.9')
33
+ s.add_development_dependency('mocha', '~> 0.13.2')
34
+ s.add_development_dependency('org-ruby', '~> 0.8.1')
35
+ s.add_development_dependency('shoulda', '~> 3.4.0')
36
+ s.add_development_dependency('wikicloth', '~> 0.8.0')
37
+ s.add_development_dependency('rake', '~> 10.0.3')
38
+ s.add_development_dependency('pry', '~> 0.9.12')
39
+ # required by pry
40
+ s.add_development_dependency('rb-readline', '~> 0.4.2')
41
+ s.add_development_dependency 'minitest-reporters', '~> 0.14.10'
42
+ s.add_development_dependency('nokogiri-diff', '~> 0.1.2')
43
+
44
+ # = MANIFEST =
45
+ s.files = %w[
46
+ Gemfile
47
+ HISTORY.md
48
+ LICENSE
49
+ README.md
50
+ Rakefile
51
+ docs/sanitization.md
52
+ gollum-lib.gemspec
53
+ lib/gollum-lib.rb
54
+ lib/gollum-lib/blob_entry.rb
55
+ lib/gollum-lib/committer.rb
56
+ lib/gollum-lib/file.rb
57
+ lib/gollum-lib/file_view.rb
58
+ lib/gollum-lib/git_access.rb
59
+ lib/gollum-lib/gitcode.rb
60
+ lib/gollum-lib/grit_ext.rb
61
+ lib/gollum-lib/helpers.rb
62
+ lib/gollum-lib/markup.rb
63
+ lib/gollum-lib/markups.rb
64
+ lib/gollum-lib/page.rb
65
+ lib/gollum-lib/pagination.rb
66
+ lib/gollum-lib/remote_code.rb
67
+ lib/gollum-lib/sanitization.rb
68
+ lib/gollum-lib/web_sequence_diagram.rb
69
+ lib/gollum-lib/wiki.rb
70
+ licenses/licenses.txt
71
+ ]
72
+ # = MANIFEST =
73
+
74
+ s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
75
+ end
@@ -0,0 +1,53 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ # stdlib
3
+ require 'digest/md5'
4
+ require 'digest/sha1'
5
+ require 'ostruct'
6
+
7
+ # external
8
+ require 'grit'
9
+ require File.expand_path('../gollum-lib/grit_ext', __FILE__)
10
+ require 'github/markup'
11
+ require 'sanitize'
12
+
13
+ # internal
14
+ require File.expand_path('../gollum-lib/git_access', __FILE__)
15
+ require File.expand_path('../gollum-lib/committer', __FILE__)
16
+ require File.expand_path('../gollum-lib/pagination', __FILE__)
17
+ require File.expand_path('../gollum-lib/blob_entry', __FILE__)
18
+ require File.expand_path('../gollum-lib/wiki', __FILE__)
19
+ require File.expand_path('../gollum-lib/page', __FILE__)
20
+ require File.expand_path('../gollum-lib/file', __FILE__)
21
+ require File.expand_path('../gollum-lib/file_view', __FILE__)
22
+ require File.expand_path('../gollum-lib/markup', __FILE__)
23
+ require File.expand_path('../gollum-lib/markups', __FILE__)
24
+ require File.expand_path('../gollum-lib/sanitization', __FILE__)
25
+ require File.expand_path('../gollum-lib/web_sequence_diagram', __FILE__)
26
+
27
+ # Set ruby to UTF-8 mode
28
+ # This is required for Ruby 1.8.7 which gollum still supports.
29
+ $KCODE = 'U' if RUBY_VERSION[0,3] == '1.8'
30
+
31
+ module Gollum
32
+ VERSION = '1.0.0'
33
+
34
+ def self.assets_path
35
+ ::File.expand_path('gollum/frontend/public', ::File.dirname(__FILE__))
36
+ end
37
+
38
+ class Error < StandardError; end
39
+
40
+ class DuplicatePageError < Error
41
+ attr_accessor :dir
42
+ attr_accessor :existing_path
43
+ attr_accessor :attempted_path
44
+
45
+ def initialize(dir, existing, attempted, message = nil)
46
+ @dir = dir
47
+ @existing_path = existing
48
+ @attempted_path = attempted
49
+ super(message || "Cannot write #{@dir}/#{@attempted_path}, found #{@dir}/#{@existing_path}.")
50
+ end
51
+ end
52
+ end
53
+
@@ -0,0 +1,95 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ module Gollum
3
+ class BlobEntry
4
+ # Gets the String SHA for this blob.
5
+ attr_reader :sha
6
+
7
+ # Gets the full path String for this blob.
8
+ attr_reader :path
9
+
10
+ # Gets the Fixnum size of this blob.
11
+ attr_reader :size
12
+
13
+ # Gets the Fixnum mode of this blob.
14
+ attr_reader :mode
15
+
16
+ def initialize(sha, path, size = nil, mode = nil)
17
+ @sha = sha
18
+ @path = path
19
+ @size = size
20
+ @mode = mode
21
+ @dir = @name = @blob = nil
22
+ end
23
+
24
+ # Gets the normalized directory path String for this blob.
25
+ def dir
26
+ @dir ||= self.class.normalize_dir(::File.dirname(@path))
27
+ end
28
+
29
+ # Gets the file base name String for this blob.
30
+ def name
31
+ @name ||= ::File.basename(@path)
32
+ end
33
+
34
+ # Gets a Grit::Blob instance for this blob.
35
+ #
36
+ # repo - Grit::Repo instance for the Grit::Blob.
37
+ #
38
+ # Returns an unbaked Grit::Blob instance.
39
+ def blob(repo)
40
+ @blob ||= Grit::Blob.create(repo,
41
+ :id => @sha, :name => name, :size => @size, :mode => @mode)
42
+ end
43
+
44
+ # Gets a Page instance for this blob.
45
+ #
46
+ # wiki - Gollum::Wiki instance for the Gollum::Page
47
+ #
48
+ # Returns a Gollum::Page instance.
49
+ def page(wiki, commit)
50
+ blob = self.blob(wiki.repo)
51
+ page = wiki.page_class.new(wiki).populate(blob, self.dir)
52
+ page.version = commit
53
+ page
54
+ end
55
+
56
+ # Gets a File instance for this blob.
57
+ #
58
+ # wiki - Gollum::Wiki instance for the Gollum::File
59
+ #
60
+ # Returns a Gollum::File instance.
61
+ def file(wiki, commit)
62
+ blob = self.blob(wiki.repo)
63
+ file = wiki.file_class.new(wiki).populate(blob, self.dir)
64
+ file.version = commit
65
+ file
66
+ end
67
+
68
+ def inspect
69
+ %(#<Gollum::BlobEntry #{@sha} #{@path}>)
70
+ end
71
+
72
+ # Normalizes a given directory name for searching through tree paths.
73
+ # Ensures that a directory begins with a slash, or
74
+ #
75
+ # normalize_dir("") # => ""
76
+ # normalize_dir(".") # => ""
77
+ # normalize_dir("foo") # => "/foo"
78
+ # normalize_dir("/foo/") # => "/foo"
79
+ # normalize_dir("/") # => ""
80
+ # normalize_dir("c:/") # => ""
81
+ #
82
+ # dir - String directory name.
83
+ #
84
+ # Returns a normalized String directory name, or nil if no directory
85
+ # is given.
86
+ def self.normalize_dir(dir)
87
+ return '' if dir =~ /^.:\/$/
88
+ if dir
89
+ dir = ::File.expand_path(dir, '/')
90
+ dir = '' if dir == '/'
91
+ end
92
+ dir
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,236 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+ module Gollum
3
+ # Responsible for handling the commit process for a Wiki. It sets up the
4
+ # Git index, provides methods for modifying the tree, and stores callbacks
5
+ # to be fired after the commit has been made. This is specifically
6
+ # designed to handle multiple updated pages in a single commit.
7
+ class Committer
8
+ # Gets the instance of the Gollum::Wiki that is being updated.
9
+ attr_reader :wiki
10
+
11
+ # Gets a Hash of commit options.
12
+ attr_reader :options
13
+
14
+ # Initializes the Committer.
15
+ #
16
+ # wiki - The Gollum::Wiki instance that is being updated.
17
+ # options - The commit Hash details:
18
+ # :message - The String commit message.
19
+ # :name - The String author full name.
20
+ # :email - The String email address.
21
+ # :parent - Optional Grit::Commit parent to this update.
22
+ # :tree - Optional String SHA of the tree to create the
23
+ # index from.
24
+ # :committer - Optional Gollum::Committer instance. If provided,
25
+ # assume that this operation is part of batch of
26
+ # updates and the commit happens later.
27
+ #
28
+ # Returns the Committer instance.
29
+ def initialize(wiki, options = {})
30
+ @wiki = wiki
31
+ @options = options
32
+ @callbacks = []
33
+ end
34
+
35
+ # Public: References the Git index for this commit.
36
+ #
37
+ # Returns a Grit::Index.
38
+ def index
39
+ @index ||= begin
40
+ idx = @wiki.repo.index
41
+ if tree = options[:tree]
42
+ idx.read_tree(tree)
43
+ elsif parent = parents.first
44
+ idx.read_tree(parent.tree.id)
45
+ end
46
+ idx
47
+ end
48
+ end
49
+
50
+ # Public: The committer for this commit.
51
+ #
52
+ # Returns a Grit::Actor.
53
+ def actor
54
+ @actor ||= begin
55
+ @options[:name] = @wiki.default_committer_name if @options[:name].to_s.empty?
56
+ @options[:email] = @wiki.default_committer_email if @options[:email].to_s.empty?
57
+ Grit::Actor.new(@options[:name], @options[:email])
58
+ end
59
+ end
60
+
61
+ # Public: The parent commits to this pending commit.
62
+ #
63
+ # Returns an array of Grit::Commit instances.
64
+ def parents
65
+ @parents ||= begin
66
+ arr = [@options[:parent] || @wiki.repo.commit(@wiki.ref)]
67
+ arr.flatten!
68
+ arr.compact!
69
+ arr
70
+ end
71
+ end
72
+
73
+ # Adds a page to the given Index.
74
+ #
75
+ # dir - The String subdirectory of the Gollum::Page without any
76
+ # prefix or suffix slashes (e.g. "foo/bar").
77
+ # name - The String Gollum::Page filename_stripped.
78
+ # format - The Symbol Gollum::Page format.
79
+ # data - The String wiki data to store in the tree map.
80
+ # allow_same_ext - A Boolean determining if the tree map allows the same
81
+ # filename with the same extension.
82
+ #
83
+ # Raises Gollum::DuplicatePageError if a matching filename already exists.
84
+ # This way, pages are not inadvertently overwritten.
85
+ #
86
+ # Returns nothing (modifies the Index in place).
87
+ def add_to_index(dir, name, format, data, allow_same_ext = false)
88
+ # spaces must be dashes
89
+ dir.gsub!(' ', '-')
90
+ name.gsub!(' ', '-')
91
+
92
+ path = @wiki.page_file_name(name, format)
93
+
94
+ dir = '/' if dir.strip.empty?
95
+
96
+ fullpath = ::File.join(*[@wiki.page_file_dir, dir, path].compact)
97
+ fullpath = fullpath[1..-1] if fullpath =~ /^\//
98
+
99
+ if index.current_tree && tree = index.current_tree / (@wiki.page_file_dir || '/')
100
+ tree = tree / dir unless tree.nil?
101
+ end
102
+
103
+ if tree
104
+ downpath = path.downcase.sub(/\.\w+$/, '')
105
+
106
+ tree.blobs.each do |blob|
107
+ next if page_path_scheduled_for_deletion?(index.tree, fullpath)
108
+
109
+ existing_file = blob.name.downcase.sub(/\.\w+$/, '')
110
+ existing_file_ext = ::File.extname(blob.name).sub(/^\./, '')
111
+
112
+ new_file_ext = ::File.extname(path).sub(/^\./, '')
113
+
114
+ if downpath == existing_file && !(allow_same_ext && new_file_ext == existing_file_ext)
115
+ raise DuplicatePageError.new(dir, blob.name, path)
116
+ end
117
+ end
118
+ end
119
+
120
+ fullpath = fullpath.force_encoding('ascii-8bit') if fullpath.respond_to?(:force_encoding)
121
+
122
+ index.add(fullpath, @wiki.normalize(data))
123
+ end
124
+
125
+ # Update the given file in the repository's working directory if there
126
+ # is a working directory present.
127
+ #
128
+ # dir - The String directory in which the file lives.
129
+ # name - The String name of the page or the stripped filename
130
+ # (should be pre-canonicalized if required).
131
+ # format - The Symbol format of the page.
132
+ #
133
+ # Returns nothing.
134
+ def update_working_dir(dir, name, format)
135
+ unless @wiki.repo.bare
136
+ if @wiki.page_file_dir
137
+ dir = dir.size.zero? ? @wiki.page_file_dir : ::File.join(dir, @wiki.page_file_dir)
138
+ end
139
+
140
+ path =
141
+ if dir == ''
142
+ @wiki.page_file_name(name, format)
143
+ else
144
+ ::File.join(dir, @wiki.page_file_name(name, format))
145
+ end
146
+
147
+ path = path.force_encoding('ascii-8bit') if path.respond_to?(:force_encoding)
148
+
149
+ Dir.chdir(::File.join(@wiki.repo.path, '..')) do
150
+ if file_path_scheduled_for_deletion?(index.tree, path)
151
+ @wiki.repo.git.rm({'f' => true}, '--', path)
152
+ else
153
+ @wiki.repo.git.checkout({}, 'HEAD', '--', path)
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ # Writes the commit to Git and runs the after_commit callbacks.
160
+ #
161
+ # Returns the String SHA1 of the new commit.
162
+ def commit
163
+ sha1 = index.commit(@options[:message], parents, actor, nil, @wiki.ref)
164
+ @callbacks.each do |cb|
165
+ cb.call(self, sha1)
166
+ end
167
+ sha1
168
+ end
169
+
170
+ # Adds a callback to be fired after a commit.
171
+ #
172
+ # block - A block that expects this Committer instance and the created
173
+ # commit's SHA1 as the arguments.
174
+ #
175
+ # Returns nothing.
176
+ def after_commit(&block)
177
+ @callbacks << block
178
+ end
179
+
180
+ # Determine if a given page (regardless of format) is scheduled to be
181
+ # deleted in the next commit for the given Index.
182
+ #
183
+ # map - The Hash map:
184
+ # key - The String directory or filename.
185
+ # val - The Hash submap or the String contents of the file.
186
+ # path - The String path of the page file. This may include the format
187
+ # extension in which case it will be ignored.
188
+ #
189
+ # Returns the Boolean response.
190
+ def page_path_scheduled_for_deletion?(map, path)
191
+ parts = path.split('/')
192
+ if parts.size == 1
193
+ deletions = map.keys.select { |k| !map[k] }
194
+ downfile = parts.first.downcase.sub(/\.\w+$/, '')
195
+ deletions.any? { |d| d.downcase.sub(/\.\w+$/, '') == downfile }
196
+ else
197
+ part = parts.shift
198
+ if rest = map[part]
199
+ page_path_scheduled_for_deletion?(rest, parts.join('/'))
200
+ else
201
+ false
202
+ end
203
+ end
204
+ end
205
+
206
+ # Determine if a given file is scheduled to be deleted in the next commit
207
+ # for the given Index.
208
+ #
209
+ # map - The Hash map:
210
+ # key - The String directory or filename.
211
+ # val - The Hash submap or the String contents of the file.
212
+ # path - The String path of the file including extension.
213
+ #
214
+ # Returns the Boolean response.
215
+ def file_path_scheduled_for_deletion?(map, path)
216
+ parts = path.split('/')
217
+ if parts.size == 1
218
+ deletions = map.keys.select { |k| !map[k] }
219
+ deletions.any? { |d| d == parts.first }
220
+ else
221
+ part = parts.shift
222
+ if rest = map[part]
223
+ file_path_scheduled_for_deletion?(rest, parts.join('/'))
224
+ else
225
+ false
226
+ end
227
+ end
228
+ end
229
+
230
+ # Proxies methods t
231
+ def method_missing(name, *args)
232
+ args.map! { |item| item.respond_to?(:force_encoding) ? item.force_encoding('ascii-8bit') : item }
233
+ index.send(name, *args)
234
+ end
235
+ end
236
+ end