rtfm 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.markdown +97 -0
- data/Rakefile +89 -0
- data/VERSION +1 -0
- data/lib/rtfm.rb +20 -0
- data/lib/rtfm/groffstring.rb +45 -0
- data/lib/rtfm/manpage.rb +71 -0
- data/lib/rtfm/option.rb +37 -0
- data/lib/rtfm/sections/authors.rb +25 -0
- data/lib/rtfm/sections/description.rb +32 -0
- data/lib/rtfm/sections/see_also.rb +24 -0
- data/lib/rtfm/sections/synopsis.rb +41 -0
- data/lib/rtfm/sections/text.rb +10 -0
- data/lib/rtfm/tasks.rb +44 -0
- data/lib/rubygems_plugin.rb +171 -0
- data/man/testing.2 +54 -0
- data/spec/authors_spec.rb +23 -0
- data/spec/description_spec.rb +55 -0
- data/spec/groffstring_spec.rb +42 -0
- data/spec/rtfm_spec.rb +53 -0
- data/spec/see_also_spec.rb +35 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/synopsis_spec.rb +43 -0
- metadata +109 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Michael Edgar
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# rtfm
|
2
|
+
|
3
|
+
Using RTFM, you can declaratively create nice, standard man pages for your
|
4
|
+
Ruby projects using a slick, maintainable DSL. It also includes rake tasks
|
5
|
+
to aid in debugging, generating, and installing your man files.
|
6
|
+
|
7
|
+
## Normal manfiles are... interesting
|
8
|
+
|
9
|
+
You might say: "but wait, aren't man pages already written in a DSL?", and you'd
|
10
|
+
be right! However, here's an example of it:
|
11
|
+
|
12
|
+
.It Fl p
|
13
|
+
Acts mostly same as -n switch, but print the value of variable
|
14
|
+
.Li "$_"
|
15
|
+
at the each end of the loop. For example:
|
16
|
+
.Bd -literal -offset indent
|
17
|
+
% echo matz | ruby -p -e '$_.tr! "a-z", "A-Z"'
|
18
|
+
MATZ
|
19
|
+
.Ed
|
20
|
+
.Pp
|
21
|
+
.It Fl r Ar library
|
22
|
+
Causes Ruby to load the library using require. It is useful when using
|
23
|
+
.Fl n
|
24
|
+
or
|
25
|
+
.Fl p .
|
26
|
+
|
27
|
+
That's from the Ruby manfile. This is using the `groff` macro language,
|
28
|
+
which is awfully spiffy. However, it makes man files extremely tedious to
|
29
|
+
maintain. It even spits out errors if you put a blank line in your manfile!
|
30
|
+
|
31
|
+
## A word of caution
|
32
|
+
|
33
|
+
Now, manfiles are long and complex, and contain a lot of information. Chances
|
34
|
+
are, your RTFM-based manfile isn't actually going to be too much shorter than
|
35
|
+
your normal groff-based entry. The difference is that by using the RTFM
|
36
|
+
DSL, it should be very, very simple to maintain. Which is a huge
|
37
|
+
win for your users.
|
38
|
+
|
39
|
+
## Example Manual Page:
|
40
|
+
|
41
|
+
RTFM::ManPage.new("testing", 2) do |page|
|
42
|
+
page.summary = "testing man page"
|
43
|
+
page.option :verbose, "The verbose flag does a lot of stuff."
|
44
|
+
page.option :silliness, "Set how silly the application should be.", :argument => "n"
|
45
|
+
page.option :input, "The input flag takes a filename", :argument => "<input>"
|
46
|
+
|
47
|
+
page.description do |desc|
|
48
|
+
desc.body = "This is a small, temporary description of the testing " +
|
49
|
+
"man page."
|
50
|
+
end
|
51
|
+
page.see_also do |also|
|
52
|
+
also.reference "rails", 1
|
53
|
+
also.reference "ruby"
|
54
|
+
end
|
55
|
+
page.bugs = "There are a few bugs, but nothing too serious."
|
56
|
+
page.history = "This program has a storied history that I am too " +
|
57
|
+
"lazy to include here."
|
58
|
+
page.authors do |authors|
|
59
|
+
authors.add "Michael Edgar", "adgar@carboni.ca"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
## Other wins
|
64
|
+
|
65
|
+
The weird thing about making manfiles is that each section has its own semantics -
|
66
|
+
sometimes, macros even change their meanings slightly. There are idioms and "best practices"
|
67
|
+
for each. The cool part of RTFM is that we can try to match the idioms for you - you
|
68
|
+
just provide the information we need.
|
69
|
+
|
70
|
+
An example: in the "SEE ALSO" section, you can provide a list of other manual pages
|
71
|
+
that are related to yours. In the example above, you see a couple of simple references.
|
72
|
+
If you read the deep, dark documentation on the subject, you'll know that these references
|
73
|
+
should be sorted by manual section, and then alphabetically within sections. RTFM will do that
|
74
|
+
for you. It's the little things that count.
|
75
|
+
|
76
|
+
## Upcoming
|
77
|
+
|
78
|
+
Hopefully we can get some of this integrated into RubyGems, though that's a long shot -
|
79
|
+
it's a long-standing, cross-platform project. But it's nice to dream.
|
80
|
+
|
81
|
+
I hope to add the ability to insert raw groff if you are an advanced user and want some
|
82
|
+
really spiffy formatting.
|
83
|
+
|
84
|
+
## Note on Patches/Pull Requests
|
85
|
+
|
86
|
+
* Fork the project.
|
87
|
+
* Make your feature addition or bug fix.
|
88
|
+
* Add tests for it. This is important so I don't break it in a
|
89
|
+
future version unintentionally.
|
90
|
+
* Commit, do not mess with rakefile, version, or history.
|
91
|
+
(if you want to have your own version, that is fine but
|
92
|
+
bump version in a commit by itself I can ignore when I pull)
|
93
|
+
* Send me a pull request. Bonus points for topic branches.
|
94
|
+
|
95
|
+
## Copyright
|
96
|
+
|
97
|
+
Copyright (c) 2010 Michael Edgar. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "rtfm"
|
8
|
+
gem.summary = "Create makefiles declaratively. Comes with rake tasks."
|
9
|
+
gem.description = <<-EOF
|
10
|
+
Using RTFM, you can declaratively create nice, standard man pages for your
|
11
|
+
Ruby projects using a slick, maintainable DSL. It also includes rake tasks
|
12
|
+
to aid in debugging, generating, and installing your man files.
|
13
|
+
EOF
|
14
|
+
gem.email = "michael.j.edgar@dartmouth.edu"
|
15
|
+
gem.homepage = "http://github.com/michaeledgar/rtfm"
|
16
|
+
gem.authors = ["Michael Edgar"]
|
17
|
+
gem.add_development_dependency "bacon", ">= 0"
|
18
|
+
gem.add_development_dependency "yard", ">= 0"
|
19
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
20
|
+
end
|
21
|
+
Jeweler::GemcutterTasks.new
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'rake/testtask'
|
27
|
+
Rake::TestTask.new(:spec) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
spec.verbose = true
|
31
|
+
end
|
32
|
+
|
33
|
+
begin
|
34
|
+
require 'rcov/rcovtask'
|
35
|
+
Rcov::RcovTask.new do |test|
|
36
|
+
test.libs << 'test'
|
37
|
+
test.pattern = 'test/**/test_*.rb'
|
38
|
+
test.verbose = true
|
39
|
+
end
|
40
|
+
rescue LoadError
|
41
|
+
task :rcov do
|
42
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
task :spec => :check_dependencies
|
47
|
+
|
48
|
+
task :default => :spec
|
49
|
+
|
50
|
+
begin
|
51
|
+
require 'yard'
|
52
|
+
YARD::Rake::YardocTask.new
|
53
|
+
rescue LoadError
|
54
|
+
task :yardoc do
|
55
|
+
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), "lib"))
|
60
|
+
require 'rtfm'
|
61
|
+
require 'rtfm/tasks'
|
62
|
+
|
63
|
+
RTFM::ManPage.new("testing", 2) do |page|
|
64
|
+
page.summary = "testing man page"
|
65
|
+
page.option :r, "Some r flag"
|
66
|
+
page.option :j, "Some j flag"
|
67
|
+
page.option :k, "Some k flag"
|
68
|
+
page.option :"0", "Some zero flag"
|
69
|
+
page.option :A, "Some capitalized flag"
|
70
|
+
page.option :Z, "some big-z flag"
|
71
|
+
page.option :verbose, "The verbose flag does a lot of stuff."
|
72
|
+
page.option :silliness, "Set how silly the application should be.", :argument => "n"
|
73
|
+
page.option :input, "The input flag takes a filename", :argument => "<input>"
|
74
|
+
|
75
|
+
page.description do |desc|
|
76
|
+
desc.body = "This is a small, temporary description of the testing " +
|
77
|
+
"man page."
|
78
|
+
end
|
79
|
+
page.see_also do |also|
|
80
|
+
also.reference "rails", 1
|
81
|
+
also.reference "ruby"
|
82
|
+
end
|
83
|
+
page.bugs = "There are a few bugs, but nothing too serious."
|
84
|
+
page.history = "This program has a storied history that I am too " +
|
85
|
+
"lazy to include here."
|
86
|
+
page.authors do |section|
|
87
|
+
section.author "Michael Edgar", "adgar@carboni.ca"
|
88
|
+
end
|
89
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.5.0
|
data/lib/rtfm.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
$:.unshift File.expand_path(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
if RUBY_VERSION < "1.9"
|
4
|
+
class String
|
5
|
+
unless method_defined?(:ord)
|
6
|
+
def ord
|
7
|
+
self[0]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'rtfm/groffstring'
|
14
|
+
require 'rtfm/option'
|
15
|
+
|
16
|
+
Dir[File.expand_path(File.join(File.dirname(__FILE__), "rtfm", "sections", "**"))].each do |f|
|
17
|
+
require f
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rtfm/manpage'
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module RTFM
|
2
|
+
class GroffString
|
3
|
+
|
4
|
+
attr_reader :source
|
5
|
+
|
6
|
+
def self.groffify(str = "")
|
7
|
+
out = self.new(str)
|
8
|
+
yield out
|
9
|
+
out.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(str = "")
|
13
|
+
@source = str.dup
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
source
|
18
|
+
end
|
19
|
+
|
20
|
+
def rstrip
|
21
|
+
source.rstrip
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_line(line)
|
25
|
+
source << line.rstrip << "\n"
|
26
|
+
end
|
27
|
+
alias_method :<<, :add_line
|
28
|
+
|
29
|
+
def section(section)
|
30
|
+
self.Sh section.upcase
|
31
|
+
end
|
32
|
+
|
33
|
+
def put_name
|
34
|
+
self.Nm
|
35
|
+
end
|
36
|
+
|
37
|
+
def reference(page, section = nil)
|
38
|
+
self.Xr page, (section || "")
|
39
|
+
end
|
40
|
+
|
41
|
+
def method_missing(meth, *args, &block)
|
42
|
+
add_line ".#{meth} #{args.join(" ")}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/rtfm/manpage.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
module RTFM
|
2
|
+
class ManPage < Struct.new(:name, :section, :date, :summary)
|
3
|
+
class << self
|
4
|
+
def text_section(*args)
|
5
|
+
args.each do |sect|
|
6
|
+
class_eval %Q{
|
7
|
+
def #{sect}
|
8
|
+
@#{sect} ||= TextSection.new(:#{sect}, "")
|
9
|
+
end
|
10
|
+
def #{sect}=(str)
|
11
|
+
@#{sect} = TextSection.new(:#{sect}, str)
|
12
|
+
end
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
alias_method :text_sections, :text_section
|
17
|
+
|
18
|
+
def add_section(name, klass)
|
19
|
+
klass = klass.to_s.intern
|
20
|
+
class_eval %Q{
|
21
|
+
def #{name}
|
22
|
+
@#{name} ||= #{klass}.new
|
23
|
+
yield @#{name} if block_given?
|
24
|
+
@#{name}
|
25
|
+
end
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def all_pages
|
30
|
+
@pages ||= []
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
text_section :bugs, :diagnostics, :compatibility, :standards, :history
|
35
|
+
add_section :see_also, SeeAlsoSection
|
36
|
+
add_section :description, DescriptionSection
|
37
|
+
add_section :authors, AuthorsSection
|
38
|
+
add_section :synopsis, SynopsisSection
|
39
|
+
|
40
|
+
def initialize(name, section=nil)
|
41
|
+
self.class.all_pages << self
|
42
|
+
self.name, self.section = name, section
|
43
|
+
self.date = DateTime.now
|
44
|
+
yield self
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_option(name, desc, opts={})
|
48
|
+
opt = Option.new(name, desc, opts)
|
49
|
+
description.add_option opt
|
50
|
+
unless opts.has_key?(:synopsis) && !opts.delete(:synopsis)
|
51
|
+
synopsis.add_option(opt)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
alias_method :option, :add_option
|
55
|
+
|
56
|
+
def to_groff
|
57
|
+
GroffString.groffify do |out|
|
58
|
+
out.Dd date.strftime("%B %d, %Y")
|
59
|
+
out.Os
|
60
|
+
out.Dt name, (section || "")
|
61
|
+
out.section "NAME"
|
62
|
+
out.Nm name
|
63
|
+
out.Nd summary
|
64
|
+
[@synopsis, @description, @see_also, @history, @authors, @bugs].each do |sect|
|
65
|
+
out << sect.to_groff if sect
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
data/lib/rtfm/option.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module RTFM
|
2
|
+
class Option < Struct.new(:title, :desc, :opts)
|
3
|
+
def title
|
4
|
+
super.to_s
|
5
|
+
end
|
6
|
+
|
7
|
+
def argument
|
8
|
+
opts && (opts[:argument] || opts[:arg])
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_groff(how)
|
12
|
+
GroffString.groffify do |out|
|
13
|
+
args = [:Fl, self.title]
|
14
|
+
|
15
|
+
if self.argument
|
16
|
+
argument = self.argument.to_s
|
17
|
+
if argument[0,1] == "<" && argument[-1,1] == ">"
|
18
|
+
args << "Ao" << argument[1..-2] << "Ac"
|
19
|
+
elsif argument[0,1] == "[" && argument[-1,1] == "]"
|
20
|
+
args << "Oo" << argument[1..-2] << "Oc"
|
21
|
+
else
|
22
|
+
args << :Ar << argument
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
case how
|
27
|
+
when :option
|
28
|
+
out.Op *args
|
29
|
+
when :item
|
30
|
+
out.Pp
|
31
|
+
out.It *args
|
32
|
+
out << self.desc
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RTFM
|
2
|
+
class AuthorsSection
|
3
|
+
def initialize
|
4
|
+
@authors = []
|
5
|
+
yield self if block_given?
|
6
|
+
end
|
7
|
+
def add_author(name, email = nil)
|
8
|
+
@authors << {:name => name, :email => email}
|
9
|
+
end
|
10
|
+
alias_method :author, :add_author
|
11
|
+
alias_method :add, :add_author
|
12
|
+
|
13
|
+
def to_groff
|
14
|
+
GroffString.groffify do |out|
|
15
|
+
out.section "authors"
|
16
|
+
@authors.each do |author|
|
17
|
+
args = ["\"#{author[:name]}\""]
|
18
|
+
if author[:email] then args << "Aq" << author[:email] end
|
19
|
+
out.An *args
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module RTFM
|
2
|
+
class DescriptionSection < Struct.new(:body, :options)
|
3
|
+
def initialize(*args)
|
4
|
+
super
|
5
|
+
self.options ||= []
|
6
|
+
yield self if block_given?
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_option(*args)
|
10
|
+
if args.size == 1 && args.first.is_a?(Option)
|
11
|
+
then self.options << args.first
|
12
|
+
else self.options << Option.new(*args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
alias_method :option, :add_option
|
16
|
+
|
17
|
+
def to_groff
|
18
|
+
GroffString.groffify do |out|
|
19
|
+
out.section "description"
|
20
|
+
out << self.body
|
21
|
+
if options.any?
|
22
|
+
out.Bl "-tag", "-width", "\"mmmmmmmmmm\"", "-compact"
|
23
|
+
options.each do |option|
|
24
|
+
out << option.to_groff(:item)
|
25
|
+
end
|
26
|
+
out.El
|
27
|
+
out.Pp
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RTFM
|
2
|
+
class SeeAlsoSection
|
3
|
+
def initialize
|
4
|
+
@references = {}
|
5
|
+
yield self if block_given?
|
6
|
+
end
|
7
|
+
def reference(title, section = 0)
|
8
|
+
(@references[section] ||= []) << title
|
9
|
+
end
|
10
|
+
def to_groff
|
11
|
+
GroffString.groffify do |out|
|
12
|
+
out.section "SEE ALSO"
|
13
|
+
@references.keys.sort.each do |section|
|
14
|
+
@references[section].sort.each do |title|
|
15
|
+
if section == 0
|
16
|
+
then out.reference title
|
17
|
+
else out.reference title, section
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module RTFM
|
2
|
+
class SynopsisSection
|
3
|
+
def initialize
|
4
|
+
@options = []
|
5
|
+
yield self if block_given?
|
6
|
+
end
|
7
|
+
|
8
|
+
def add_option(*args)
|
9
|
+
if args.size == 1 && args.first.is_a?(Option)
|
10
|
+
then @options << args.first
|
11
|
+
else @options << Option.new(*args)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
alias_method :option, :add_option
|
15
|
+
|
16
|
+
def compare_flags(a, b)
|
17
|
+
a_ord, b_ord = a.ord, b.ord
|
18
|
+
if ('0'.ord .. '9'.ord).include?(a_ord)
|
19
|
+
a_ord += 'z'.ord
|
20
|
+
end
|
21
|
+
if ('0'.ord .. '9'.ord).include?(b_ord)
|
22
|
+
b_ord += 'z'.ord
|
23
|
+
end
|
24
|
+
a_ord <=> b_ord
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_groff
|
28
|
+
flags = @options.select {|opt| opt.title.size == 1 && !opt.argument}
|
29
|
+
long_args = @options - flags
|
30
|
+
|
31
|
+
GroffString.groffify do |out|
|
32
|
+
out.section "synopsis"
|
33
|
+
out.put_name
|
34
|
+
out.Op "Fl", flags.map {|flag| flag.title}.sort {|a, b| compare_flags(a,b)}.join
|
35
|
+
long_args.each do |opt|
|
36
|
+
out << opt.to_groff(:option)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/rtfm/tasks.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rtfm'
|
3
|
+
|
4
|
+
namespace :man do
|
5
|
+
desc "Display your man files in man."
|
6
|
+
task :debug do
|
7
|
+
require 'tempfile'
|
8
|
+
require 'rtfm'
|
9
|
+
RTFM::ManPage.all_pages.each do |page|
|
10
|
+
Tempfile.open("#{page.name}.#{page.section}") do |f|
|
11
|
+
f << page.to_groff
|
12
|
+
f.flush
|
13
|
+
system("man #{f.path}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Generate your manual files in the man/ directory"
|
19
|
+
task :gen do
|
20
|
+
FileUtils.makedirs "man/"
|
21
|
+
RTFM::ManPage.all_pages.each do |page|
|
22
|
+
File.open("man/#{page.name}.#{page.section}", "w") do |f|
|
23
|
+
f << page.to_groff
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Install your manual files globally"
|
29
|
+
task :install => :gen do
|
30
|
+
if Rake.application.unix?
|
31
|
+
Dir["man/*"].each do |manfile|
|
32
|
+
section = manfile.split(".").last
|
33
|
+
begin
|
34
|
+
FileUtils.cp(manfile, "/usr/share/man/man#{section}/")
|
35
|
+
rescue Errno::EACCES
|
36
|
+
puts "I'm sorry, but you need root privileges to install man pages with this version"+
|
37
|
+
" of RTFM."
|
38
|
+
end
|
39
|
+
end
|
40
|
+
else
|
41
|
+
raise "Can't install man pages without a unix-based OS."
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'rubygems/command_manager'
|
2
|
+
|
3
|
+
require 'rubygems/command'
|
4
|
+
require 'rubygems_analyzer'
|
5
|
+
|
6
|
+
class Gem::Commands::ManCommand < Gem::Command
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super 'man', 'Manage man-files bundled with gems'
|
10
|
+
options[:action] = :install
|
11
|
+
|
12
|
+
add_option('-v', '--view', "Views the manual files included in",
|
13
|
+
"the gem.") do |value, options|
|
14
|
+
options[:action] = :view
|
15
|
+
end
|
16
|
+
|
17
|
+
add_option('-i', '--install', "Installs all the gem's manual files globally") do |value, options|
|
18
|
+
options[:action] = :install
|
19
|
+
end
|
20
|
+
|
21
|
+
add_option('-r', '--remove', "Removes the gem's manual files globally") do |value, options|
|
22
|
+
options[:action] = :remove
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def execute
|
27
|
+
if Gem.win_platform? || !has_man?
|
28
|
+
alert_error "You must have the 'man' command to use this extension."
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
get_all_gem_names.each do |name|
|
33
|
+
path = get_path name, options[:version]
|
34
|
+
if path then
|
35
|
+
man_path = File.join path, 'man'
|
36
|
+
if File.exist?(man_path) && File.directory?(man_path) then
|
37
|
+
Dir[File.join man_path, "**"].each do |man_file|
|
38
|
+
dispatch(man_file)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
alert_error "Gem '#{name}' does not appear to have packaged man files."
|
42
|
+
end
|
43
|
+
else
|
44
|
+
alert_error "Gem '#{name}' not installed."
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def dispatch(file)
|
51
|
+
case options[:action]
|
52
|
+
when :install
|
53
|
+
install(file)
|
54
|
+
when :view
|
55
|
+
view(file)
|
56
|
+
when :remove
|
57
|
+
remove(file)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
MAN_DIR = "/usr/share/man/"
|
63
|
+
|
64
|
+
##
|
65
|
+
# Views the man file in the man program
|
66
|
+
def view(source)
|
67
|
+
system("man #{source}")
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Installs the given file into the appropriate man directory.
|
72
|
+
def install(source)
|
73
|
+
full_name = File.split(source).last
|
74
|
+
section = full_name.split(".").last
|
75
|
+
destination = File.join MAN_DIR, "man#{section}", full_name
|
76
|
+
File.open(destination, "wb") do |out|
|
77
|
+
out << watermark_file(source)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Installs the given file into the appropriate man directory.
|
83
|
+
def remove(source)
|
84
|
+
full_name = File.split(source).last
|
85
|
+
section = full_name.split(".").last
|
86
|
+
destination = File.join MAN_DIR, "man#{section}", full_name
|
87
|
+
if is_watermarked_file?(destination)
|
88
|
+
FileUtils.unlink(destination)
|
89
|
+
else
|
90
|
+
alert_error "The man file at #{destination} was not installed by Rubygems. It has "+
|
91
|
+
"not been deleted."
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def watermark
|
96
|
+
%Q{.\\" Installed by Rubygems' Man Extension\n}
|
97
|
+
end
|
98
|
+
|
99
|
+
##
|
100
|
+
# Watermarks a man page. Assumes input file is not already compressed.
|
101
|
+
def watermark_file(file)
|
102
|
+
add_watermark(File.read(file))
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# Watermarks some groff text, so you can tell it's been rubygem'd
|
107
|
+
def add_watermark(text)
|
108
|
+
"#{watermark}#{text}"
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# Watermarks a man page. Assumes input file is not already compressed.
|
113
|
+
def is_watermarked_file?(file)
|
114
|
+
is_watermarked?(File.read(file))
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# Is the given text watermarked?
|
119
|
+
def is_watermarked?(text)
|
120
|
+
text[0..(watermark.size-1)] == watermark
|
121
|
+
end
|
122
|
+
|
123
|
+
# Return the full path to the cached gem file matching the given
|
124
|
+
# name and version requirement. Returns 'nil' if no match.
|
125
|
+
#
|
126
|
+
# Example:
|
127
|
+
#
|
128
|
+
# get_path('rake', '> 0.4') # -> '/usr/lib/ruby/gems/1.8/cache/rake-0.4.2.gem'
|
129
|
+
# get_path('rake', '< 0.1') # -> nil
|
130
|
+
# get_path('rak') # -> nil (exact name required)
|
131
|
+
#--
|
132
|
+
# TODO: This should be refactored so that it's a general service. I don't
|
133
|
+
# think any of our existing classes are the right place though. Just maybe
|
134
|
+
# 'Cache'?
|
135
|
+
#
|
136
|
+
# TODO: It just uses Gem.dir for now. What's an easy way to get the list of
|
137
|
+
# source directories?
|
138
|
+
def get_path(gemname, version_req)
|
139
|
+
return gemname if gemname =~ /\.gem$/i
|
140
|
+
|
141
|
+
specs = Gem::source_index.find_name gemname, version_req
|
142
|
+
|
143
|
+
selected = specs.sort_by { |s| s.version }.last
|
144
|
+
|
145
|
+
return nil if selected.nil?
|
146
|
+
|
147
|
+
# We expect to find (basename).gem in the 'cache' directory.
|
148
|
+
# Furthermore, the name match must be exact (ignoring case).
|
149
|
+
if gemname =~ /^#{selected.name}$/i
|
150
|
+
filename = selected.full_name
|
151
|
+
path = nil
|
152
|
+
|
153
|
+
Gem.path.find do |gem_dir|
|
154
|
+
path = File.join gem_dir, 'gems', filename
|
155
|
+
File.exist? path
|
156
|
+
end
|
157
|
+
|
158
|
+
path
|
159
|
+
else
|
160
|
+
nil
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def has_man?
|
165
|
+
system("man 1>/dev/null 2>&1")
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
Gem::CommandManager.instance.register_command :man
|
171
|
+
|
data/man/testing.2
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
.\" Hello it's a comment
|
2
|
+
.Dd January 09, 2010
|
3
|
+
.Os
|
4
|
+
.Dt testing 2
|
5
|
+
.Sh NAME
|
6
|
+
.Nm testing
|
7
|
+
.Nd testing man page
|
8
|
+
.Sh SYNOPSIS
|
9
|
+
.Nm
|
10
|
+
.Op Fl AZjkr0
|
11
|
+
.Op Fl verbose
|
12
|
+
.Op Fl silliness Ar n
|
13
|
+
.Op Fl input Ao input Ac
|
14
|
+
.Sh DESCRIPTION
|
15
|
+
This is a small, temporary description of the testing man page.
|
16
|
+
.Bl -tag -width "mmmmmmmmmm" -compact
|
17
|
+
.Pp
|
18
|
+
.It Fl r
|
19
|
+
Some r flag
|
20
|
+
.Pp
|
21
|
+
.It Fl j
|
22
|
+
Some j flag
|
23
|
+
.Pp
|
24
|
+
.It Fl k
|
25
|
+
Some k flag
|
26
|
+
.Pp
|
27
|
+
.It Fl 0
|
28
|
+
Some zero flag
|
29
|
+
.Pp
|
30
|
+
.It Fl A
|
31
|
+
Some capitalized flag
|
32
|
+
.Pp
|
33
|
+
.It Fl Z
|
34
|
+
some big-z flag
|
35
|
+
.Pp
|
36
|
+
.It Fl verbose
|
37
|
+
The verbose flag does a lot of stuff.
|
38
|
+
.Pp
|
39
|
+
.It Fl silliness Ar n
|
40
|
+
Set how silly the application should be.
|
41
|
+
.Pp
|
42
|
+
.It Fl input Ao input Ac
|
43
|
+
The input flag takes a filename
|
44
|
+
.El
|
45
|
+
.Pp
|
46
|
+
.Sh SEE ALSO
|
47
|
+
.Xr ruby
|
48
|
+
.Xr rails 1
|
49
|
+
.Sh HISTORY
|
50
|
+
This program has a storied history that I am too lazy to include here.
|
51
|
+
.Sh AUTHORS
|
52
|
+
.An "Michael Edgar" Aq adgar@carboni.ca
|
53
|
+
.Sh BUGS
|
54
|
+
There are a few bugs, but nothing too serious.
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "authors section" do
|
4
|
+
before do
|
5
|
+
@authors = AuthorsSection.new do |sect|
|
6
|
+
sect.author "Michael Edgar"
|
7
|
+
sect.author "Ari Brown", "seydar@carboni.ca"
|
8
|
+
end
|
9
|
+
@groffed = @authors.to_groff
|
10
|
+
end
|
11
|
+
|
12
|
+
it "makes an authors section" do
|
13
|
+
@groffed.should.match(/^\.Sh AUTHORS$/)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "adds an author without an email" do
|
17
|
+
@groffed.should.match(/^\.An "Michael Edgar"$/)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "adds an author with an email" do
|
21
|
+
@groffed.should.match(/^\.An "Ari Brown" Aq seydar@carboni.ca/)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "description section" do
|
4
|
+
|
5
|
+
FULL_DESC = "This is the description for the description section. Typically, this would" +
|
6
|
+
" be much longer, but for now, it is short. Huzzah!"
|
7
|
+
|
8
|
+
before do
|
9
|
+
@desc = DescriptionSection.new do |desc|
|
10
|
+
desc.body = FULL_DESC
|
11
|
+
desc.option :verbose, "Makes output wordy and unnecessarily long"
|
12
|
+
desc.option :input, "Specifies an input file", :arg => "<file>"
|
13
|
+
desc.option :output, "Specifies an output file", :argument => "[output]"
|
14
|
+
desc.option :silly, "Has a silly argument", :arg => "silliness"
|
15
|
+
end
|
16
|
+
@groffed = @desc.to_groff
|
17
|
+
end
|
18
|
+
|
19
|
+
it "creates a description section" do
|
20
|
+
@groffed.should.match(/^\.Sh DESCRIPTION$/)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "displays its body below the section header" do
|
24
|
+
@groffed.should.match(/^\.Sh DESCRIPTION\nThis is the/)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "contains the full body text" do
|
28
|
+
@groffed.should.include(FULL_DESC)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "creates a list for options" do
|
32
|
+
@groffed.should.match(/^\.Bl -tag/)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "creates list items with option names" do
|
36
|
+
@groffed.should.match(/^\.It Fl verbose/)
|
37
|
+
@groffed.should.match(/^\.It Fl input/)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "displays arguments for options" do
|
41
|
+
@groffed.should.match(/^\.It Fl silly Ar silliness/)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "changes arguments with angle brackets to proper groff" do
|
45
|
+
@groffed.should.match(/Ao file Ac/)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "changes arguments with square brackets to proper groff" do
|
49
|
+
@groffed.should.match(/Oo output Oc/)
|
50
|
+
end
|
51
|
+
it "puts option descriptions next to option names" do
|
52
|
+
@groffed.should.match(/^\.It Fl verbose\nMakes output wordy/)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "groff_string" do
|
4
|
+
before do
|
5
|
+
@groff = GroffString.new
|
6
|
+
@groff_with_line = GroffString.new("Some text")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "uses its initial value" do
|
10
|
+
@groff.to_s.should.equal ""
|
11
|
+
@groff_with_line.to_s.should.equal("Some text")
|
12
|
+
end
|
13
|
+
|
14
|
+
it "converts to a string" do
|
15
|
+
@groff.should.respond_to(:to_s)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "adds references using the .Xr macro" do
|
19
|
+
@groff.reference("rails", 1)
|
20
|
+
@groff.to_s.should.include(".Xr rails 1")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "generates sections" do
|
24
|
+
@groff.section("NAME")
|
25
|
+
@groff.to_s.should.include(".Sh NAME")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "generates arbitrary macros" do
|
29
|
+
@groff.Br("some", "arguments", :here)
|
30
|
+
@groff.to_s.should.include(".Br some arguments here")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "adds lines using add_line" do
|
34
|
+
@groff.add_line("some arbitrary line goes here")
|
35
|
+
@groff.to_s.should.include("some arbitrary line goes here\n")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "adds lines with <<" do
|
39
|
+
@groff << "werd some line"
|
40
|
+
@groff.to_s.should.include("werd some line\n")
|
41
|
+
end
|
42
|
+
end
|
data/spec/rtfm_spec.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "rtfm" do
|
4
|
+
before do
|
5
|
+
@rtfm = ManPage.new("testing", 2) do |page|
|
6
|
+
page.date = Date.parse("1/2/2010")
|
7
|
+
page.summary = "testing man page"
|
8
|
+
page.see_also do |also|
|
9
|
+
also.reference "madeup", 4
|
10
|
+
also.reference "rails", 1
|
11
|
+
also.reference "ruby"
|
12
|
+
also.reference "perl", 1
|
13
|
+
end
|
14
|
+
page.bugs = "There are a few bugs, but nothing too serious."
|
15
|
+
page.history = "This program has a storied history that I am too lazy to include here."
|
16
|
+
end
|
17
|
+
@groff = @rtfm.to_groff
|
18
|
+
end
|
19
|
+
|
20
|
+
it "displays the correct date" do
|
21
|
+
@groff.should.match(/^\.Dd January 02, 2010$/)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "has a NAME section" do
|
25
|
+
@groff.should.match(/^\.Sh NAME$/)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "generates a name line" do
|
29
|
+
@groff.should.match(/^\.Nm testing/)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "generates a summary line" do
|
33
|
+
@groff.should.match(/^\.Nd testing man page/)
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "rtfm-sections" do
|
37
|
+
it "has a bugs section" do
|
38
|
+
@groff.should.match(/^\.Sh BUGS$/)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "includes its bugs text" do
|
42
|
+
@groff.should.match(/^There are a few bugs/)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "has a history section" do
|
46
|
+
@groff.should.match(/^\.Sh HISTORY$/)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "includes its history text" do
|
50
|
+
@groff.should.match(/^This program has a storied history/)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "see also section" do
|
4
|
+
before do
|
5
|
+
@see_also = SeeAlsoSection.new do |also|
|
6
|
+
also.reference "madeup", 4
|
7
|
+
also.reference "rails", 1
|
8
|
+
also.reference "ruby"
|
9
|
+
also.reference "perl", 1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "has a see also section" do
|
14
|
+
@see_also.to_groff.should.match(/^\.Sh SEE ALSO/)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "includes references in its see also section" do
|
18
|
+
groffed = @see_also.to_groff
|
19
|
+
groffed.should.match(/^\.Xr rails 1$/)
|
20
|
+
groffed.should.match(/^\.Xr ruby$/)
|
21
|
+
groffed.should.match(/^\.Xr perl 1$/)
|
22
|
+
groffed.should.match(/^\.Xr madeup 4$/)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "sorts by section" do
|
26
|
+
groffed = @see_also.to_groff
|
27
|
+
groffed.index(/^\.Xr ruby$/).should.be < groffed.index(/^\.Xr rails 1$/)
|
28
|
+
groffed.index(/^\.Xr rails 1$/).should.be < groffed.index(/^\.Xr madeup 4$/)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "sorts within sections" do
|
32
|
+
groffed = @see_also.to_groff
|
33
|
+
groffed.index(/^\.Xr perl 1$/).should.be < groffed.index(/^\.Xr rails 1$/)
|
34
|
+
end
|
35
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "synopsis section" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@synopsis = SynopsisSection.new do |syno|
|
7
|
+
syno.option :r, "Some r flag"
|
8
|
+
syno.option :j, "Some j flag"
|
9
|
+
syno.option :k, "Some k flag"
|
10
|
+
syno.option :"0", "Some zero flag"
|
11
|
+
syno.option :A, "Some capitalized flag"
|
12
|
+
syno.option :Z, "some big-z flag"
|
13
|
+
syno.option :verbose, "The verbose flag does a lot of stuff."
|
14
|
+
syno.option :silliness, "Set how silly the application should be.", :argument => "n"
|
15
|
+
syno.option :input, "The input flag takes a filename", :argument => "<input>"
|
16
|
+
end
|
17
|
+
@groffed = @synopsis.to_groff
|
18
|
+
end
|
19
|
+
|
20
|
+
it "contains the name of the man page" do
|
21
|
+
@groffed.should.match(/^\.Nm$/)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "displays long-form flags" do
|
25
|
+
@groffed.should.match(/^\.Op Fl verbose$/)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "combines short-form flags into one entry" do
|
29
|
+
@groffed.should.match(/^\.Op Fl ([rjk0AZ]{6})/)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "sorts short-form flags within their entry" do
|
33
|
+
@groffed.should.match(/AZjkr0/)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "encodes < and > in option arguments" do
|
37
|
+
@groffed.should.match(/Ao input Ac/)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "underlines arguments" do
|
41
|
+
@groffed.should.match(/\.Op Fl silliness Ar n/)
|
42
|
+
end
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rtfm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Edgar
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-10 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: bacon
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: yard
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description: |
|
36
|
+
Using RTFM, you can declaratively create nice, standard man pages for your
|
37
|
+
Ruby projects using a slick, maintainable DSL. It also includes rake tasks
|
38
|
+
to aid in debugging, generating, and installing your man files.
|
39
|
+
|
40
|
+
email: michael.j.edgar@dartmouth.edu
|
41
|
+
executables: []
|
42
|
+
|
43
|
+
extensions: []
|
44
|
+
|
45
|
+
extra_rdoc_files:
|
46
|
+
- LICENSE
|
47
|
+
- README.markdown
|
48
|
+
files:
|
49
|
+
- .document
|
50
|
+
- .gitignore
|
51
|
+
- LICENSE
|
52
|
+
- README.markdown
|
53
|
+
- Rakefile
|
54
|
+
- VERSION
|
55
|
+
- lib/rtfm.rb
|
56
|
+
- lib/rtfm/groffstring.rb
|
57
|
+
- lib/rtfm/manpage.rb
|
58
|
+
- lib/rtfm/option.rb
|
59
|
+
- lib/rtfm/sections/authors.rb
|
60
|
+
- lib/rtfm/sections/description.rb
|
61
|
+
- lib/rtfm/sections/see_also.rb
|
62
|
+
- lib/rtfm/sections/synopsis.rb
|
63
|
+
- lib/rtfm/sections/text.rb
|
64
|
+
- lib/rtfm/tasks.rb
|
65
|
+
- lib/rubygems_plugin.rb
|
66
|
+
- man/testing.2
|
67
|
+
- spec/authors_spec.rb
|
68
|
+
- spec/description_spec.rb
|
69
|
+
- spec/groffstring_spec.rb
|
70
|
+
- spec/rtfm_spec.rb
|
71
|
+
- spec/see_also_spec.rb
|
72
|
+
- spec/spec_helper.rb
|
73
|
+
- spec/synopsis_spec.rb
|
74
|
+
has_rdoc: true
|
75
|
+
homepage: http://github.com/michaeledgar/rtfm
|
76
|
+
licenses: []
|
77
|
+
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options:
|
80
|
+
- --charset=UTF-8
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: "0"
|
88
|
+
version:
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: "0"
|
94
|
+
version:
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 1.3.5
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: Create makefiles declaratively. Comes with rake tasks.
|
102
|
+
test_files:
|
103
|
+
- spec/authors_spec.rb
|
104
|
+
- spec/description_spec.rb
|
105
|
+
- spec/groffstring_spec.rb
|
106
|
+
- spec/rtfm_spec.rb
|
107
|
+
- spec/see_also_spec.rb
|
108
|
+
- spec/spec_helper.rb
|
109
|
+
- spec/synopsis_spec.rb
|