man_parser 0.1.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.
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