man_parser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
@@ -0,0 +1,42 @@
1
+ Parse man source
2
+
3
+ Install
4
+ =======
5
+ sudo gem install grosser-man_parser -s http://gems.github.com/
6
+
7
+ Usage
8
+ =====
9
+ ManParser.parse('ls')
10
+ # all the sections
11
+ :sections=>{
12
+ "NAME"=>"printf \\- format and print data",
13
+ "SYNOPSIS"=>".B printf\n\\f...",
14
+ "AUTHOR"=>"Written by David MacKenzie.",
15
+ ...
16
+ },
17
+
18
+ # options parsed into :name, :alias, :argument, :description
19
+ :options=>[
20
+ {:name=>"help", :description=>"display this help and exit"},
21
+ {:name=>"version", :description=>"output version information and exit"},
22
+ {:alias=>"Z", :name => 'context', :description=>"print any SELinux security context of each file"}
23
+ ],
24
+
25
+ # description without options
26
+ :description=>".PPPrint ARGUMENT(s) according to FORMAT\n bla bla...."}
27
+
28
+ ### available_commands
29
+ ManParser.available_commands => array of commands that are available for parsing
30
+
31
+ ### source
32
+ ManParser.source('ls') => uncleaned source of man file
33
+
34
+ TODO
35
+ ====
36
+ - add to_html("\fBxx\fR") == "<b>xx</b>"
37
+
38
+ Author
39
+ ======
40
+ [Michael Grosser](http://pragmatig.wordpress.com)
41
+ grosser.michael@gmail.com
42
+ Hereby placed under public domain, do what you want, just do not hold me accountable...
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ desc "Run all specs in spec directory"
2
+ task :default do
3
+ options = "--colour --format progress --loadby --reverse"
4
+ files = FileList['spec/**/*_spec.rb']
5
+ system("spec #{options} #{files}")
6
+ end
7
+
8
+ begin
9
+ require 'jeweler'
10
+ project_name = 'man_parser'
11
+ Jeweler::Tasks.new do |gem|
12
+ gem.name = project_name
13
+ gem.summary = "Parse unix man pages into ruby-readable format"
14
+ gem.email = "grosser.michael@gmail.com"
15
+ gem.homepage = "http://github.com/grosser/#{project_name}"
16
+ gem.authors = ["Michael Grosser"]
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
21
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/lib/man_parser.rb ADDED
@@ -0,0 +1,95 @@
1
+ class ManParser
2
+ def self.available_commands
3
+ `ls #{root}`.split("\n").map{|c| c.sub('.1.gz','')}
4
+ end
5
+
6
+ def self.source(cmd)
7
+ `gzip -dc #{root}/#{cmd}.1.gz`
8
+ end
9
+
10
+ def self.parse(cmd)
11
+ sections = sections(source(cmd))
12
+ description, options = parse_description(sections['DESCRIPTION'])
13
+ options = options.map{|option| parse_option(option*' ') }
14
+ {:description => description.map{|l|l.strip}.join(''), :options=>options, :sections=>sections}
15
+ end
16
+
17
+ private
18
+
19
+ def self.root
20
+ '/usr/share/man/man1'
21
+ end
22
+
23
+ def self.parse_option(option)
24
+ option = option.gsub(/\\f[IB](.*?)\\fR/,"\\1").gsub('\\','')
25
+
26
+ found = if option =~ /^-(\w+), --([-\w]+)(=(\w+))?(.*)/
27
+ {:alias=>$1, :name=>$2, :argument=>$4, :description=>$5}
28
+ elsif option =~ /^--([-\w]+)(=(\w+))?(.*)/
29
+ {:name=>$1, :argument=>$3, :description=>$4}
30
+ elsif option =~ /^-([-\w]+)(.*)/
31
+ {:alias=>$1, :description=>$2}
32
+ end
33
+
34
+ if not found
35
+ puts "#{option} <-> nil !"
36
+ return
37
+ end
38
+
39
+ found[:description] = found[:description].to_s.strip.sub(/\s*\.TP$/,'')
40
+ found.delete(:argument) unless found[:argument]
41
+
42
+ found
43
+ end
44
+
45
+ # description can be split like "description, options, descriptions"
46
+ # so we remove the options part, and combind the 2 descriptions parts
47
+ def self.parse_description(text)
48
+ in_option = false
49
+ already_switched = false
50
+ options = []
51
+ description = []
52
+
53
+ text.split("\n")[1..-1].each do |line|
54
+
55
+ if start_of_option?(line) and not already_switched
56
+ in_option = true
57
+ options << [] #new option
58
+ elsif line =~ /^\.PP/ and in_option
59
+ already_switched = true
60
+ in_option = false
61
+ end
62
+
63
+ next if line.strip.empty?
64
+
65
+ if in_option
66
+ options.last << line
67
+ else
68
+ description << line
69
+ end
70
+ end
71
+
72
+ [description * "\n", options]
73
+ end
74
+
75
+ # split into sections according to "SectionHead" aka .SH
76
+ def self.sections(text)
77
+ name = 'OUT_OF_SECTION'
78
+ sections = Hash.new([])
79
+
80
+ text.split("\n").each do |line|
81
+ if line =~ /^\.SH (.*)$/
82
+ name = $1
83
+ else
84
+ sections[name] += [line]
85
+ end
86
+ end
87
+
88
+ sections.each{|k,v| sections[k] = v*"\n"}
89
+ sections
90
+ end
91
+
92
+ def self.start_of_option?(line)
93
+ !!( line =~ /^\\fB\\-/)
94
+ end
95
+ end
@@ -0,0 +1,45 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{man_parser}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Grosser"]
12
+ s.date = %q{2009-10-03}
13
+ s.email = %q{grosser.michael@gmail.com}
14
+ s.extra_rdoc_files = [
15
+ "README.markdown"
16
+ ]
17
+ s.files = [
18
+ "README.markdown",
19
+ "Rakefile",
20
+ "VERSION",
21
+ "lib/man_parser.rb",
22
+ "man_parser.gemspec",
23
+ "spec/man_parser_spec.rb",
24
+ "spec/spec_helper.rb"
25
+ ]
26
+ s.homepage = %q{http://github.com/grosser/man_parser}
27
+ s.rdoc_options = ["--charset=UTF-8"]
28
+ s.require_paths = ["lib"]
29
+ s.rubygems_version = %q{1.3.5}
30
+ s.summary = %q{Parse unix man pages into ruby-readable format}
31
+ s.test_files = [
32
+ "spec/man_parser_spec.rb",
33
+ "spec/spec_helper.rb"
34
+ ]
35
+
36
+ if s.respond_to? :specification_version then
37
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
38
+ s.specification_version = 3
39
+
40
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
41
+ else
42
+ end
43
+ else
44
+ end
45
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ManParser do
4
+ describe :parse do
5
+ it "finds the description" do
6
+ d = ManParser.parse('ls')[:description]
7
+ d.should =~ /^\.PPList information about the FILEs \(the current/
8
+ d.should =~ /problems, 2 if serious trouble\.$/
9
+ d.should_not include('\\-\\-all')
10
+ d.should_not include('do not ignore entries starting with')
11
+ d.should_not include(" ")
12
+ end
13
+
14
+ describe 'options' do
15
+ def options
16
+ ManParser.parse('ls')[:options]
17
+ end
18
+
19
+ it "finds all options" do
20
+ options.size.should == 58
21
+ end
22
+
23
+ it "extracts the name" do
24
+ options.first[:name].should == 'all'
25
+ end
26
+
27
+ it "extracts the alias" do
28
+ options.first[:alias].should == 'a'
29
+ end
30
+
31
+ it "extracts the description" do
32
+ options.first[:description].should == 'do not ignore entries starting with .'
33
+ end
34
+
35
+ it "understands format with only name (--author)" do
36
+ options[2].should == {:name=>'author', :description=>'with -l, print the author of each file'}
37
+ end
38
+ end
39
+ end
40
+
41
+ describe :source do
42
+ it "reads the source" do
43
+ ManParser.source('printf').should =~ /^.\\\" DO NOT MODIFY THIS F(.*) access to the complete manual.\n$/m
44
+ end
45
+ end
46
+
47
+ describe :available_commands do
48
+ it "finds them" do
49
+ ManParser.available_commands.should include('printf')
50
+ end
51
+ end
52
+
53
+ describe :parse_option do
54
+ def parse(x)
55
+ ManParser.send(:parse_option, x)
56
+ end
57
+
58
+ it "parses single --" do
59
+ x = parse('\fB\-\-help\fR display this help and exit .TP')
60
+ x.should == {:name=>"help", :description=>"display this help and exit"}
61
+ end
62
+
63
+ it "parses single -- with =" do
64
+ x = parse('\fB\-\-block\-size\fR=\fISIZE\fR xyz')
65
+ x.should == {:name => 'block-size', :argument=>'SIZE', :description=>"xyz"}
66
+ end
67
+
68
+ it "parses single -" do
69
+ x = parse('\fB\-1\fR list one file per line .TP')
70
+ x.should == {:alias=>"1", :description=>"list one file per line"}
71
+ end
72
+
73
+ it "parses - and --" do
74
+ x = parse('\fB\-Z\fR, \fB\-\-context\fR print any SELinux security context of each file .TP')
75
+ x.should == {:alias=>"Z", :name => 'context', :description=>"print any SELinux security context of each file"}
76
+ end
77
+
78
+ it "parses - and -- with =" do
79
+ x = parse('\fB\-T\fR, \fB\-\-tabsize\fR=\fICOLS\fR assume tab stops at each COLS instead of 8 .TP')
80
+ x.should == {:alias=>"T", :name => 'tabsize', :argument=>'COLS', :description=>"assume tab stops at each COLS instead of 8"}
81
+ end
82
+
83
+ it "does not parse random stuff" do
84
+ ManParser.stub!(:puts)
85
+ x = parse('as we say: \fB\-T\fR, \fB\-\-tabsize\fR=\fICOLS\fR assume tab stops at each COLS instead of 8')
86
+ x.should == nil
87
+ end
88
+ end
89
+
90
+ describe :start_of_option? do
91
+ {
92
+ '\fB\-\-version\fR'=>true,
93
+ '\fB\-1\fR'=>true,
94
+ '\fB\-\-color\fR=\fIauto\fR'=>true,
95
+ '\fB\-T\fR, \fB\-\-tabsize\fR=\fICOLS\fR'=>true,
96
+ '\fB\-U\fR'=>true,
97
+ '\-\-\-\-\-'=>false,
98
+ ' asdadas'=>false
99
+ }.each do |line, success|
100
+ it "recognises #{line} -- #{success}" do
101
+ ManParser.send(:start_of_option?, line).should == success
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,4 @@
1
+ # ---- requirements
2
+ $LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
3
+
4
+ require 'man_parser'
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: man_parser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael Grosser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-03 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: grosser.michael@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.markdown
24
+ files:
25
+ - README.markdown
26
+ - Rakefile
27
+ - VERSION
28
+ - lib/man_parser.rb
29
+ - man_parser.gemspec
30
+ - spec/man_parser_spec.rb
31
+ - spec/spec_helper.rb
32
+ has_rdoc: true
33
+ homepage: http://github.com/grosser/man_parser
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options:
38
+ - --charset=UTF-8
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.3.5
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: Parse unix man pages into ruby-readable format
60
+ test_files:
61
+ - spec/man_parser_spec.rb
62
+ - spec/spec_helper.rb