deblank 0.0.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.
data/README.md ADDED
@@ -0,0 +1,88 @@
1
+ deblank - remove special characters from filenames
2
+ ==================================================
3
+
4
+ `deblank` is a command line tool (written in [Ruby][Ruby])
5
+ that renames files and replaces or removes special characters
6
+ like spaces, parentheses, or umlauts.
7
+ The new filename will only contain the following characters:
8
+
9
+ A-Z a-z 0-9 . _ -
10
+
11
+ Spaces are replaced by underscores, German umlauts and eszett are
12
+ transliterated, all other invalid characters are removed.
13
+
14
+ Examples
15
+ --------
16
+
17
+ Use the program as shown in the examples below.
18
+
19
+ * `deblank "no space (and parentheses) allowed.txt"`
20
+
21
+ renames the file to `no_space_and_parentheses_allowed.txt`
22
+
23
+ * `deblank "path with spaces/schrödinger.jpg"`
24
+
25
+ renames the file to `path with spaces/schroedinger.jpg`
26
+
27
+ * `deblank -n "no space.txt"`
28
+
29
+ no-act mode, only shows what would happen
30
+
31
+ * `deblank -l`
32
+
33
+ lists the used character substitutions
34
+
35
+ Installation
36
+ ------------
37
+
38
+ You can either
39
+
40
+ - use `gem install deblank`,
41
+
42
+ - copy `lib/deblank.rb` under the name `deblank` into your search path,
43
+
44
+ - clone or download the repository and use `[sudo] rake install`
45
+ on a Linux machine to install `deblank` and its man page to `/usr/local`.
46
+
47
+ Requirements
48
+ ------------
49
+
50
+ - Ruby must be installed on your system.
51
+
52
+ - No additional Ruby gems are needed to run `deblank`.
53
+
54
+ - `deblank` has been tested with Ruby 1.9.3 on a Linux machine
55
+ and on Windows (command prompt with code page 850).
56
+
57
+ Documentation
58
+ -------------
59
+
60
+ Use `deblank --help` to display a brief help message.
61
+
62
+ If you installed `deblank` using `rake install` you can read
63
+ its man page with `man deblank`.
64
+
65
+ Known problems
66
+ --------------
67
+
68
+ With the Windows command prompt, depending on the used character
69
+ code page there might occur problems due to misinterpreted encoding
70
+ of command line arguments.
71
+
72
+ Reporting bugs
73
+ --------------
74
+
75
+ Report bugs on the `deblank` home page: <https://github.com/stomar/deblank/>
76
+
77
+ License
78
+ -------
79
+
80
+ Copyright &copy; 2012, Marcus Stollsteimer
81
+
82
+ `deblank` is free software: you can redistribute it and/or modify
83
+ it under the terms of the GNU General Public License version 3 or later (GPLv3+),
84
+ see [www.gnu.org/licenses/gpl.html](http://www.gnu.org/licenses/gpl.html).
85
+ There is NO WARRANTY, to the extent permitted by law.
86
+
87
+
88
+ [Ruby]: http://www.ruby-lang.org/
data/Rakefile ADDED
@@ -0,0 +1,73 @@
1
+ # rakefile for the deblank script.
2
+ #
3
+ # Copyright (C) 2012 Marcus Stollsteimer
4
+
5
+ require 'rake/testtask'
6
+
7
+ require './lib/deblank'
8
+
9
+ PROGNAME = Deblank::PROGNAME
10
+ HOMEPAGE = Deblank::HOMEPAGE
11
+ TAGLINE = Deblank::TAGLINE
12
+
13
+ BINDIR = '/usr/local/bin'
14
+ MANDIR = '/usr/local/man/man1'
15
+
16
+ HELP2MAN = 'help2man'
17
+ SED = 'sed'
18
+
19
+ BINARY = 'lib/deblank.rb'
20
+ BINARYNAME = 'deblank' # install using this name
21
+ MANPAGE = 'man/deblank.1'
22
+ H2MFILE = 'deblank.h2m'
23
+
24
+
25
+ def gemspec_file
26
+ 'deblank.gemspec'
27
+ end
28
+
29
+
30
+ task :default => [:test]
31
+
32
+ Rake::TestTask.new do |t|
33
+ t.libs << '.'
34
+ t.pattern = 'test/**/test_*.rb'
35
+ t.ruby_opts << '-rubygems'
36
+ t.verbose = true
37
+ t.warning = true
38
+ end
39
+
40
+
41
+ desc 'Install binary and man page'
42
+ task :install => [BINARY, MANPAGE] do
43
+ mkdir_p BINDIR
44
+ install(BINARY, "#{BINDIR}/#{BINARYNAME}")
45
+ mkdir_p MANDIR
46
+ install(MANPAGE, MANDIR, :mode => 0644)
47
+ end
48
+
49
+
50
+ desc 'Uninstall binary and man page'
51
+ task :uninstall do
52
+ rm "#{BINDIR}/#{BINARYNAME}"
53
+ manfile = File.basename(MANPAGE)
54
+ rm "#{MANDIR}/#{manfile}"
55
+ end
56
+
57
+
58
+ desc 'Create man page'
59
+ task :man => [MANPAGE]
60
+
61
+ file MANPAGE => [BINARY, H2MFILE] do
62
+ sh "#{HELP2MAN} --no-info --name='#{TAGLINE}' --include=#{H2MFILE} -o #{MANPAGE} ./#{BINARY}"
63
+ sh "#{SED} -i '/\.PP/{N;s/\.PP\\nOptions/.SH OPTIONS/}' #{MANPAGE}"
64
+ sh "#{SED} -i 's/^License GPL/.br\\nLicense GPL/;s/There is NO WARRANTY/.br\\nThere is NO WARRANTY/' #{MANPAGE}"
65
+ sh "#{SED} -i 's!%HOMEPAGE%!#{HOMEPAGE}!g' #{MANPAGE}"
66
+ sh "#{SED} -i 's!%PROGNAME%!#{PROGNAME}!g' #{MANPAGE}"
67
+ end
68
+
69
+
70
+ desc 'Build gem'
71
+ task :build => [MANPAGE] do
72
+ sh "gem build #{gemspec_file}"
73
+ end
data/bin/deblank ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ require 'deblank'
4
+
5
+ Deblank::Application.new.run!
data/deblank.gemspec ADDED
@@ -0,0 +1,43 @@
1
+ require './lib/deblank'
2
+
3
+ version = Deblank::VERSION
4
+ date = Deblank::DATE
5
+ homepage = Deblank::HOMEPAGE
6
+ tagline = Deblank::TAGLINE
7
+
8
+ Gem::Specification.new do |s|
9
+ s.name = 'deblank'
10
+ s.version = version
11
+ s.date = date
12
+ s.rubyforge_project = 'deblank'
13
+
14
+ s.description = 'deblank is a command line tool that ' +
15
+ 'renames files and replaces or removes special characters ' +
16
+ 'like spaces, parentheses, or umlauts.'
17
+ s.summary = "deblank - #{tagline}"
18
+
19
+ s.authors = ['Marcus Stollsteimer']
20
+ s.email = 'sto.mar@web.de'
21
+ s.homepage = homepage
22
+
23
+ s.license = 'GPL-3'
24
+
25
+ # s.requirements = ''
26
+
27
+ s.executables = ['deblank']
28
+ s.bindir = 'bin'
29
+ s.require_path = 'lib'
30
+ s.test_files = Dir.glob('test/**/test_*.rb')
31
+
32
+ s.rdoc_options = ['--charset=UTF-8']
33
+
34
+ s.files = %w{
35
+ README.md
36
+ Rakefile
37
+ deblank.gemspec
38
+ deblank.h2m
39
+ } +
40
+ Dir.glob('{bin,lib,man,test}/**/*')
41
+
42
+ s.add_development_dependency('rake')
43
+ end
data/deblank.h2m ADDED
@@ -0,0 +1,3 @@
1
+ [See also]
2
+ The full documentation for %PROGNAME% is available on
3
+ the project home page: <%HOMEPAGE%>.
data/lib/deblank.rb ADDED
@@ -0,0 +1,243 @@
1
+ #!/usr/bin/ruby -w
2
+ # encoding: UTF-8
3
+ # == Name
4
+ #
5
+ # deblank - remove special characters from filenames
6
+ #
7
+ # == Description
8
+ #
9
+ # +deblank+ renames files and replaces or removes special characters
10
+ # like spaces, parentheses, or umlauts.
11
+ #
12
+ # == See also
13
+ #
14
+ # Use <tt>deblank --help</tt> to display a brief help message.
15
+ #
16
+ # == Author
17
+ #
18
+ # Copyright (C) 2012 Marcus Stollsteimer
19
+ #
20
+ # License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
21
+
22
+ require 'optparse'
23
+
24
+ # This module contains the classes for the +deblank+ tool.
25
+ module Deblank
26
+
27
+ PROGNAME = 'deblank'
28
+ VERSION = '0.0.1'
29
+ DATE = '2012-12-20'
30
+ HOMEPAGE = 'https://github.com/stomar/deblank'
31
+ TAGLINE = 'remove special characters from filenames'
32
+
33
+ COPYRIGHT = "Copyright (C) 2012 Marcus Stollsteimer.\n" +
34
+ "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n" +
35
+ "This is free software: you are free to change and redistribute it.\n" +
36
+ "There is NO WARRANTY, to the extent permitted by law."
37
+
38
+ # Parser for the command line options.
39
+ # The class method parse! does the job.
40
+ class Optionparser
41
+
42
+ # Parses the command line options from +argv+.
43
+ # (+argv+ is cleared).
44
+ # Might print out help or version information.
45
+ #
46
+ # +argv+ - array with the command line options
47
+ #
48
+ # Returns a hash containing the option parameters.
49
+ def self.parse!(argv)
50
+
51
+ options = {
52
+ :files => nil,
53
+ :simulate => false,
54
+ }
55
+
56
+ opt_parser = OptionParser.new do |opt|
57
+ opt.banner = "Usage: #{PROGNAME} [options] file[s]"
58
+ opt.separator ''
59
+ opt.separator 'deblank renames files and replaces or removes special characters'
60
+ opt.separator 'like spaces, parentheses, or umlauts.'
61
+ opt.separator 'The new filename will only contain the following characters:'
62
+ opt.separator ''
63
+ opt.separator ' ' << NameConverter::VALID_CHARS
64
+ opt.separator ''
65
+ opt.separator 'Spaces are replaced by underscores, German umlauts and eszett are'
66
+ opt.separator 'transliterated, all other invalid characters are removed.'
67
+ opt.separator ''
68
+ opt.separator 'Options'
69
+ opt.separator ''
70
+
71
+ # process --version and --help first,
72
+ # exit successfully (GNU Coding Standards)
73
+ opt.on_tail('-h', '--help', 'Print a brief help message and exit.') do
74
+ puts opt_parser
75
+ puts "\nReport bugs on the #{PROGNAME} home page: <#{HOMEPAGE}>"
76
+ exit
77
+ end
78
+
79
+ opt.on_tail('-v', '--version',
80
+ 'Print a brief version information and exit.') do
81
+ puts "#{PROGNAME} #{VERSION}"
82
+ puts COPYRIGHT
83
+ exit
84
+ end
85
+
86
+ opt.on('-l', '--list',
87
+ 'List the used character substitutions.') do
88
+ puts NameConverter.substitutions_to_string
89
+ exit
90
+ end
91
+
92
+ opt.on('-n', '--no-act',
93
+ 'Do not rename files, only display what would happen.') do
94
+ options[:simulate] = true
95
+ end
96
+
97
+ opt.separator ''
98
+ end
99
+ opt_parser.parse!(argv)
100
+
101
+ # only file[s] should be left (at least 1 argument)
102
+ raise(ArgumentError, 'wrong number of arguments') if argv.size < 1
103
+
104
+ options[:files] = Array.new(argv).map do |filename|
105
+ correct_encoding(filename).encode('UTF-8')
106
+ end
107
+ argv.clear
108
+
109
+ options
110
+ end
111
+
112
+ # Corrects the encoding for (seemingly) CP850 encoded strings
113
+ # from `CP850' to `Windows-1252'.
114
+ #
115
+ # Returns a copy of +string+ with corrected encoding or +string+.
116
+ #
117
+ # [On the Windows test machine (which uses code page 850 for the
118
+ # command prompt) the command line arguments are interpreted by Ruby
119
+ # as CP850 encoded strings but actually are Windows-1252 encoded.]
120
+ def self.correct_encoding(string)
121
+ return string unless string.encoding == Encoding::CP850
122
+
123
+ string.dup.force_encoding('Windows-1252')
124
+ end
125
+ end
126
+
127
+ # This module provides a converter method for filenames
128
+ # (only the base name is modified).
129
+ module NameConverter
130
+
131
+ VALID_CHARS = 'A-Z a-z 0-9 . _ -' # spaces are ignored, `-' must be last
132
+
133
+ SUBSTITUTIONS = {
134
+ ' ' => '_',
135
+ 'ä' => 'ae',
136
+ 'ö' => 'oe',
137
+ 'ü' => 'ue',
138
+ 'Ä' => 'Ae',
139
+ 'Ö' => 'Oe',
140
+ 'Ü' => 'Ue',
141
+ 'ß' => 'ss'
142
+ }
143
+
144
+ def self.convert(filename)
145
+ invalid_chars = /[^#{VALID_CHARS.tr(' ', '')}]/
146
+ basename = File.basename(filename)
147
+ dir = File.dirname(filename)
148
+
149
+ SUBSTITUTIONS.each do |from, to|
150
+ basename.gsub!(/#{from}/, to)
151
+ end
152
+ basename.gsub!(invalid_chars, '')
153
+
154
+ dir == '.' ? basename : "#{dir}/#{basename}"
155
+ end
156
+
157
+ def self.substitutions_to_string
158
+ output = ''
159
+ SUBSTITUTIONS.each do |from, to|
160
+ output << "#{from} => #{to}\n"
161
+ end
162
+
163
+ output
164
+ end
165
+ end
166
+
167
+ # The main program. It's run! method is called
168
+ # if the script is run from the command line.
169
+ # It parses the command line arguments and renames the files.
170
+ class Application
171
+
172
+ ERRORCODE = {:general => 1, :usage => 2}
173
+
174
+ def initialize
175
+ begin
176
+ options = Optionparser.parse!(ARGV)
177
+ @files = options[:files]
178
+ @simulate = options[:simulate]
179
+ rescue => e
180
+ usage_fail(e.message)
181
+ end
182
+ end
183
+
184
+ # The main program.
185
+ def run!
186
+ message = "This is a dry run, files will not be renamed."
187
+ warn "#{message}\n#{'-' * message.size}\n" if @simulate
188
+
189
+ @files.each do |filename|
190
+ unless File.exist?(filename)
191
+ warn "There is no file `#{filename}'. (Skipped.)"
192
+ next
193
+ end
194
+
195
+ new_filename = NameConverter.convert(filename)
196
+
197
+ # filenames are identical
198
+ if new_filename == filename
199
+ warn("`#{filename}' and `#{new_filename}' are the same file. (Skipped.)")
200
+ next
201
+ end
202
+
203
+ # move file
204
+ if File.exist?(new_filename)
205
+ overwrite_ok = ask("File `#{new_filename}' already exists. Overwrite?")
206
+ next unless overwrite_ok
207
+ end
208
+
209
+ warn "Moving from `#{filename}' to `#{new_filename}'."
210
+ File.rename(filename, new_filename) unless @simulate
211
+ end # of each
212
+ end
213
+
214
+ # Asks for yes or no (y/n).
215
+ #
216
+ # +question+ - string to be printed
217
+ #
218
+ # Returns +true+ if the answer is yes.
219
+ def ask(question) # :nodoc:
220
+ loop do
221
+ $stderr.print "#{question} [y/n] "
222
+ reply = $stdin.gets.chomp.downcase # $stdin: avoids gets / ARGV problem
223
+ return true if reply == 'y'
224
+ return false if reply == 'n'
225
+ warn "Please answer `y' or `n'."
226
+ end
227
+ end
228
+
229
+ # Prints an error message and a short help information, then exits.
230
+ def usage_fail(message) # :nodoc:
231
+ warn "#{PROGNAME}: #{message}"
232
+ warn "Use `#{PROGNAME} --help' for valid options."
233
+ exit ERRORCODE[:usage]
234
+ end
235
+ end
236
+
237
+ ### call main method only if called on command line
238
+
239
+ if __FILE__ == $0
240
+ Application.new.run!
241
+ end
242
+
243
+ end # module
data/man/deblank.1 ADDED
@@ -0,0 +1,42 @@
1
+ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.4.
2
+ .TH DEBLANK "1" "December 2012" "deblank 0.0.1" "User Commands"
3
+ .SH NAME
4
+ deblank \- remove special characters from filenames
5
+ .SH SYNOPSIS
6
+ .B deblank
7
+ [\fIoptions\fR] \fIfile\fR[\fIs\fR]
8
+ .SH DESCRIPTION
9
+ deblank renames files and replaces or removes special characters
10
+ like spaces, parentheses, or umlauts.
11
+ The new filename will only contain the following characters:
12
+ .IP
13
+ A\-Z a\-z 0\-9 . _ \-
14
+ .PP
15
+ Spaces are replaced by underscores, German umlauts and eszett are
16
+ transliterated, all other invalid characters are removed.
17
+ .SH OPTIONS
18
+ .TP
19
+ \fB\-l\fR, \fB\-\-list\fR
20
+ List the used character substitutions.
21
+ .TP
22
+ \fB\-n\fR, \fB\-\-no\-act\fR
23
+ Do not rename files, only display what would happen.
24
+ .TP
25
+ \fB\-h\fR, \fB\-\-help\fR
26
+ Print a brief help message and exit.
27
+ .TP
28
+ \fB\-v\fR, \fB\-\-version\fR
29
+ Print a brief version information and exit.
30
+ .SH "REPORTING BUGS"
31
+ Report bugs on the deblank home page: <https://github.com/stomar/deblank>
32
+ .SH COPYRIGHT
33
+ Copyright \(co 2012 Marcus Stollsteimer.
34
+ .br
35
+ License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
36
+ .br
37
+ This is free software: you are free to change and redistribute it.
38
+ .br
39
+ There is NO WARRANTY, to the extent permitted by law.
40
+ .SH "SEE ALSO"
41
+ The full documentation for deblank is available on
42
+ the project home page: <https://github.com/stomar/deblank>.
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # test_nameconverter.rb: Unit tests for the deblank script.
5
+ #
6
+ # Copyright (C) 2012 Marcus Stollsteimer
7
+
8
+ require 'minitest/spec'
9
+ require 'minitest/autorun'
10
+ require 'deblank'
11
+
12
+
13
+ describe Deblank::NameConverter do
14
+
15
+ before do
16
+ @nc = Deblank::NameConverter
17
+ end
18
+
19
+ it 'does not change the path name' do
20
+ @nc.convert('path with spaces/file.txt').must_equal 'path with spaces/file.txt'
21
+ end
22
+
23
+ it 'replaces spaces by underscores' do
24
+ @nc.convert('file with spaces.txt').must_equal 'file_with_spaces.txt'
25
+ end
26
+
27
+ it 'removes parentheses' do
28
+ @nc.convert('file_(another).txt').must_equal 'file_another.txt'
29
+ end
30
+
31
+ it 'transliterates umlauts and eszett' do
32
+ @nc.convert('Ä_Ö_Ü_ä_ö_ü_ß.txt').must_equal 'Ae_Oe_Ue_ae_oe_ue_ss.txt'
33
+ end
34
+ end
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # test_optionparser.rb: Unit tests for the deblank script.
5
+ #
6
+ # Copyright (C) 2012 Marcus Stollsteimer
7
+
8
+ require 'minitest/spec'
9
+ require 'minitest/autorun'
10
+ require 'deblank'
11
+
12
+
13
+ describe Deblank::Optionparser do
14
+
15
+ before do
16
+ @parser = Deblank::Optionparser
17
+ @arg = "test_ä.txt"
18
+ @arg_Win_1252_labeled_as_CP850 = "test_\xE4.txt".force_encoding('CP850')
19
+ @arg_Win_1252 = "test_\xE4.txt".force_encoding('Windows-1252')
20
+ end
21
+
22
+ it 'can correct encoding from (seemingly) CP850 to Windows-1252' do
23
+ arg = @arg_Win_1252_labeled_as_CP850
24
+ arg.encoding.must_equal Encoding::CP850
25
+ corrected_arg = @parser.correct_encoding(arg)
26
+ corrected_arg.encoding.must_equal Encoding::Windows_1252
27
+ end
28
+
29
+ it 'encodes (seemingly) CP850 encoded filenames into UTF-8' do
30
+ options = @parser.parse!([@arg_Win_1252_labeled_as_CP850])
31
+ filename = options[:files].first
32
+ filename.encoding.must_equal Encoding::UTF_8
33
+ filename.must_equal @arg
34
+ end
35
+
36
+ it 'encodes Windows-1252 encoded filenames into UTF-8' do
37
+ options = @parser.parse!([@arg_Win_1252])
38
+ filename = options[:files].first
39
+ filename.encoding.must_equal Encoding::UTF_8
40
+ filename.must_equal @arg
41
+ end
42
+
43
+ it 'encodes UTF-8 encoded filenames into UTF-8' do
44
+ options = @parser.parse!([@arg])
45
+ filename = options[:files].first
46
+ filename.encoding.must_equal Encoding::UTF_8
47
+ filename.must_equal @arg
48
+ end
49
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deblank
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Marcus Stollsteimer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: deblank is a command line tool that renames files and replaces or removes
31
+ special characters like spaces, parentheses, or umlauts.
32
+ email: sto.mar@web.de
33
+ executables:
34
+ - deblank
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - README.md
39
+ - Rakefile
40
+ - deblank.gemspec
41
+ - deblank.h2m
42
+ - bin/deblank
43
+ - lib/deblank.rb
44
+ - man/deblank.1
45
+ - test/test_nameconverter.rb
46
+ - test/test_optionparser.rb
47
+ homepage: https://github.com/stomar/deblank
48
+ licenses:
49
+ - GPL-3
50
+ post_install_message:
51
+ rdoc_options:
52
+ - --charset=UTF-8
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project: deblank
69
+ rubygems_version: 1.8.24
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: deblank - remove special characters from filenames
73
+ test_files:
74
+ - test/test_nameconverter.rb
75
+ - test/test_optionparser.rb
76
+ has_rdoc: