docbook_status 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.bnsignore ADDED
@@ -0,0 +1,18 @@
1
+ # The list of files that should be ignored by Mr Bones.
2
+ # Lines that start with '#' are comments.
3
+ #
4
+ # A .gitignore file can be used instead by setting it as the ignore
5
+ # file in your Rakefile:
6
+ #
7
+ # Bones {
8
+ # ignore_file '.gitignore'
9
+ # }
10
+ #
11
+ # For a project with a C extension, the following would be a good set of
12
+ # exclude patterns (uncomment them if you want to use them):
13
+ # *.[oa]
14
+ # *~
15
+ announcement.txt
16
+ coverage
17
+ doc
18
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+ gem "libxml-ruby", "~> 2.2.2", :require => 'xml'
3
+ gem "directory_watcher"
4
+
5
+ group :development do
6
+ gem "bones"
7
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,16 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ directory_watcher (1.4.1)
5
+ hoe (2.12.3)
6
+ rake (~> 0.8)
7
+ libxml-ruby (2.2.2)
8
+ rake (0.9.2)
9
+
10
+ PLATFORMS
11
+ ruby
12
+
13
+ DEPENDENCIES
14
+ directory_watcher
15
+ hoe
16
+ libxml-ruby (~> 2.2.2)
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.1.0 / 2011-09-07
2
+
3
+ * Initial version
4
+
data/README.txt ADDED
@@ -0,0 +1,59 @@
1
+ = docbook_status
2
+
3
+ A utility for DocBook authors/publishers showing the document structure (sections) and word count of a DocBook project. It is intended to provide an overview of a DocBook project's structure and volume while you are writing or editing it.
4
+
5
+
6
+ == Features
7
+
8
+ * lists all sections (set, book, ... section, simplesect) in a DocBook file
9
+ * calculates a word count for each section (words in paras, simparas and formalparas)
10
+ * works with included sections (XInclude)
11
+
12
+ == Examples
13
+
14
+ The package includes a comandline application, bin/docbook_status, that can be used in two ways:
15
+
16
+ to run it manually, once:
17
+ docbook_status <DocBook file>
18
+
19
+ to run the application in demon mode, continually:
20
+ docbook_status --demon --glob "*.xml" --dir "." <DocBook file>
21
+
22
+ In demon-mode the application checks the files matched by the _glob_ pattern in the directory specified by _dir_ for changes, and redisplays the document analysis whenever a change occures. The demon can be termanted by simply pressing RETURN.
23
+
24
+ == Download
25
+
26
+ https://rubygems.org/gem/docbook_status
27
+
28
+ == Requirements
29
+
30
+ * libxml2
31
+
32
+ == Install
33
+
34
+ * gem install docbook_status
35
+
36
+ == License
37
+
38
+ The MIT License
39
+
40
+ Copyright (c) 2011 Rainer Volz
41
+
42
+ Permission is hereby granted, free of charge, to any person obtaining
43
+ a copy of this software and associated documentation files (the
44
+ 'Software'), to deal in the Software without restriction, including
45
+ without limitation the rights to use, copy, modify, merge, publish,
46
+ distribute, sublicense, and/or sell copies of the Software, and to
47
+ permit persons to whom the Software is furnished to do so, subject to
48
+ the following conditions:
49
+
50
+ The above copyright notice and this permission notice shall be
51
+ included in all copies or substantial portions of the Software.
52
+
53
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
54
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
55
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
56
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
57
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
58
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
59
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+
2
+ begin
3
+ require 'bones'
4
+ rescue LoadError
5
+ abort '### Please install the "bones" gem ###'
6
+ end
7
+
8
+ task :default => 'test:run'
9
+ task 'gem:release' => 'test:run'
10
+
11
+ Bones {
12
+ name 'docbook_status'
13
+ authors 'Rainer Volz'
14
+ email 'dev@textmulch.de'
15
+ url 'http://projekte.textmuch.de/docbook_status/'
16
+ }
17
+
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env ruby
2
+ # -*-encoding:utf-8 ; mode:ruby-*-
3
+ ##
4
+ # docbook_status is the commandline application for the library.
5
+ # Its main purpose is to display the structure and word counts for DocBook 5 documents.
6
+ # docbook_status can be used in single-run mode or demon-mode. In demon_mode it stays active
7
+ # and looks for changes in the filesystem.
8
+ #
9
+
10
+ require 'rubygems'
11
+ require "bundler/setup"
12
+ require 'optparse'
13
+ require 'directory_watcher'
14
+
15
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib docbook_status]))
16
+
17
+ @demon = false
18
+ @glob = '*.xml'
19
+ @dir = '.'
20
+ @pre = []
21
+ banner = <<EOB
22
+ docbook_status, Version #{DocbookStatus.version}
23
+
24
+ Display DocBook 5 document structure and word counts.
25
+
26
+ Usage: docbook_status [--demon] [--glob <PATTERN>] [--dir <DIR>] [--pre COMMAND] <DOCBOOK-FILE>
27
+ EOB
28
+
29
+ opts = OptionParser.new
30
+ opts.banner = banner
31
+ opts.on('--demon', 'Keep running, act when files change') {|val| @demon = true}
32
+ opts.on('--glob PATTERN', String, 'File mask for demon mode, default = "*.xml"') {|val| @glob = val}
33
+ opts.on('--dir DIR', String, 'Source directory for demon mode, default = "." ') {|val| @dir = val}
34
+ opts.on('--pre COMMAND', String, 'A shell command that should be executed before') {|val| @pre << val}
35
+ rest = opts.parse(ARGV)
36
+
37
+ def run(file)
38
+ @pre.each {|cmd| system(cmd)}
39
+ doc = XML::Document.file(file)
40
+ dbs = DocbookStatus.new
41
+ if !dbs.is_docbook?(doc)
42
+ puts "Error: #{file} is apparently not DocBook 5."
43
+ return
44
+ end
45
+ doc.xinclude if dbs.has_xinclude?(doc)
46
+ sections = dbs.analyze_document(doc)
47
+ puts
48
+ puts "File: #{file}"
49
+ puts "Modified: #{File.ctime(file)}"
50
+ puts "Document structure:"
51
+ puts "%-50.50s %-16s %5s" % ['Title','Tag','Words']
52
+ puts "-"*73
53
+ sections.each do |s|
54
+ puts "%-50.50s %-16s %5d" % [(' ' * s[2])+s[0], s[3], s[1]]
55
+ end
56
+ end
57
+
58
+ def demon(file)
59
+ dw = DirectoryWatcher.new @dir, :glob => @glob, :pre_load => true
60
+ dw.interval = 5.0
61
+ dw.stable = 2
62
+ dw.persist = "dw_state.yml"
63
+ dw.add_observer {|*args|
64
+ args.each {|event|
65
+ #puts event
66
+ if event.type == :stable
67
+ run(file)
68
+ end
69
+ }
70
+ }
71
+ dw.start # loads state from dw_state.yml
72
+ STDIN.gets # when the user hits "enter" the script will terminate
73
+ dw.stop # stores state to dw_state.yml
74
+ end
75
+
76
+ # Print banner if called without arguments
77
+ if rest.length < 1
78
+ puts opts.to_s
79
+ exit 1
80
+ end
81
+
82
+ puts("docbook_status, Version #{DocbookStatus.version}")
83
+ run(rest[0])
84
+ if (@demon)
85
+ demon(rest[0])
86
+ end
87
+ exit 0
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{docbook_status}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Rainer Volz"]
9
+ s.date = %q{2011-09-08}
10
+ s.default_executable = %q{docbook_status}
11
+ s.description = %q{A utility for DocBook authors/publishers showing the document structure (sections) and word count of a DocBook project. It is intended to provide an overview of a DocBook project's structure and volume while you are writing or editing it.}
12
+ s.email = %q{dev@textmulch.de}
13
+ s.executables = ["docbook_status"]
14
+ s.extra_rdoc_files = ["History.txt", "README.txt", "bin/docbook_status"]
15
+ s.files = [".bnsignore", "Gemfile", "Gemfile.lock", "History.txt", "README.txt", "Rakefile", "bin/docbook_status", "lib/docbook_status.rb", "spec/docbook_status_spec.rb", "spec/spec_helper.rb", "test/fixtures/book.xml", "test/fixtures/chapter2.xml", "test/test_docbook_status.rb", "version.txt"]
16
+ s.homepage = %q{http://projekte.textmuch.de/docbook_status/}
17
+ s.rdoc_options = ["--main", "README.txt"]
18
+ s.require_paths = ["lib"]
19
+ s.rubyforge_project = %q{docbook_status}
20
+ s.rubygems_version = %q{1.6.2}
21
+ s.summary = %q{A utility for DocBook authors/publishers showing the document structure (sections) and word count of a DocBook project.}
22
+ s.test_files = ["test/test_docbook_status.rb"]
23
+
24
+ if s.respond_to? :specification_version then
25
+ s.specification_version = 3
26
+
27
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
28
+ s.add_development_dependency(%q<bones>, [">= 3.7.1"])
29
+ else
30
+ s.add_dependency(%q<bones>, [">= 3.7.1"])
31
+ end
32
+ else
33
+ s.add_dependency(%q<bones>, [">= 3.7.1"])
34
+ end
35
+ end
@@ -0,0 +1,143 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'xml'
4
+
5
+ # Analyzes DocBook 5 documents for document structure (sections) and text length.
6
+ #
7
+ class DocbookStatus
8
+
9
+ # :stopdoc
10
+ #
11
+ PATH = File.expand_path('../..', __FILE__) + File::SEPARATOR
12
+ LIBPATH = File.expand_path('..', __FILE__) + File::SEPARATOR
13
+ VERSION = File.read(PATH + '/version.txt').strip
14
+ HOME = File.expand_path(ENV['HOME'] || ENV['USERPROFILE'])
15
+ #
16
+ # :startdoc
17
+
18
+ # The DocBook 5 namespace URL
19
+ DOCBOOK_NS = 'http://docbook.org/ns/docbook'
20
+ # The XInclude namespace URL
21
+ XINCLUDE_NS = 'http://www.w3.org/2001/XInclude'
22
+
23
+ # Elements whose contents is counted as text
24
+ @@text_elements = ['para','simpara','formalpara']
25
+
26
+ # Section elements, following the list given in http://docbook.org/tdg5/en/html/ch02.html#roots
27
+ # except for the refsect... elements.
28
+ @@section_elements = %w[
29
+ acknowledgements appendix article
30
+ bibliography book
31
+ chapter colophon
32
+ dedication
33
+ glossary
34
+ index
35
+ preface
36
+ section sect1 sect2 sect3 sect4 set simplesect
37
+ toc
38
+ ]
39
+
40
+ def initialize
41
+ @sections = []
42
+ end
43
+
44
+ # Returns the version of docbook_status
45
+ #
46
+ def self.version
47
+ VERSION
48
+ end
49
+
50
+ # Counts the words in the contents of the given node. _Word_ in this
51
+ # context means something that is delimited by _space_ charactes and starts with
52
+ # _word_ characters (in the regexp sense).
53
+ #
54
+ def count_words(node)
55
+ words = node.content.strip.split(/[[:space:]]+/).find_all {|w| w =~ /\w+/}
56
+ words.size
57
+ end
58
+
59
+ # Find the _title_ of the current section. That element is either
60
+ # directly following or inside an _info_ element. Return the empty
61
+ # string if no title can be found.
62
+ #
63
+ def find_section_title(node)
64
+ title = node.find_first('./db:title')
65
+ if title.nil?
66
+ title = node.find_first './db:info/db:title'
67
+ end
68
+ if title.nil?
69
+ ""
70
+ else
71
+ title.content
72
+ end
73
+ end
74
+
75
+ # Check the document elements for content and type recursively,
76
+ # starting at the current node. Returns an array with paragraph and
77
+ # section maps.
78
+ #
79
+ def check_node(node, level, ctr)
80
+ if (@@text_elements.include? node.name)
81
+ ctr << {:type => :para, :level => level, :words => count_words(node)}
82
+ elsif (@@section_elements.include? node.name)
83
+ title = find_section_title(node)
84
+ ctr << {:type => :section, :level => level, :title => title, :name => node.name}
85
+ end
86
+ node.children.each {|inner_elem| check_node(inner_elem, level+1, ctr)} if node.children?
87
+ ctr
88
+ end
89
+
90
+ # Check whether the document has a DocBook default namespace
91
+ def is_docbook?(doc)
92
+ dbns = doc.root.namespaces.default
93
+ (!dbns.nil? && (dbns.href.casecmp(DOCBOOK_NS) == 0))
94
+ end
95
+
96
+ # Check whether the document has a XInclude namespace
97
+ def has_xinclude?(doc)
98
+ ret = false
99
+ doc.root.namespaces.each do |ns|
100
+ if (ns.href.casecmp(XINCLUDE_NS) == 0)
101
+ ret = true
102
+ break
103
+ end
104
+ end
105
+ ret
106
+ end
107
+
108
+ # Searches the XML document for sections and word counts. Returns an
109
+ # array of sections with their word counts.
110
+ #
111
+ def analyze_document(doc)
112
+ # Add a namespace declaration for XPath expressions
113
+ doc.root.namespaces.default_prefix = 'db'
114
+ # Analyze the document starting with the root node
115
+ doc_maps = check_node(doc.root,0,[])
116
+ @sections = []
117
+ section_name = doc_maps[0][:title]
118
+ section_type = doc_maps[0][:name]
119
+ section_ctr = 0
120
+ section_level = 0
121
+ doc_ctr = 0
122
+ #puts doc_maps.inspect
123
+ xms = doc_maps.drop(1)
124
+ # Compute word counts per section
125
+ xms.each do |m|
126
+ if (m[:type] == :para)
127
+ doc_ctr += m[:words]
128
+ section_ctr += m[:words]
129
+ else
130
+ @sections << [section_name,section_ctr,section_level,section_type]
131
+ section_name = m[:title]
132
+ section_ctr = 0
133
+ section_level = m[:level]
134
+ section_type = m[:name]
135
+ end
136
+ end
137
+ @sections << [section_name,section_ctr,section_level,section_type]
138
+ # Put the document word count near the document type
139
+ @sections[0][1] = doc_ctr
140
+ @sections
141
+ end
142
+
143
+ end
@@ -0,0 +1,6 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
3
+
4
+ describe DocbookStatus do
5
+ end
6
+
@@ -0,0 +1,15 @@
1
+
2
+ require File.expand_path(
3
+ File.join(File.dirname(__FILE__), %w[.. lib docbook_status]))
4
+
5
+ Spec::Runner.configure do |config|
6
+ # == Mock Framework
7
+ #
8
+ # RSpec uses it's own mocking framework by default. If you prefer to
9
+ # use mocha, flexmock or RR, uncomment the appropriate line:
10
+ #
11
+ # config.mock_with :mocha
12
+ # config.mock_with :flexmock
13
+ # config.mock_with :rr
14
+ end
15
+
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <book xmlns="http://docbook.org/ns/docbook"
3
+ xmlns:xi="http://www.w3.org/2001/XInclude"
4
+ version="5.0">
5
+ <title>B1</title>
6
+ <chapter>
7
+ <title>C1</title>
8
+ <para>
9
+ Dies ist ein Test .. Dies ist ein Test.
10
+ In den Jahren 1900-1901 geschahen viele Überfälle von O`Reillys.
11
+ </para>
12
+ </chapter>
13
+ <xi:include href="chapter2.xml"/>
14
+ </book>
@@ -0,0 +1,7 @@
1
+ <chapter xmlns="http://docbook.org/ns/docbook" version="5.0">
2
+ <title>C2</title>
3
+ <para>
4
+ Dies ist ein Test .. Dies ist ein Test.
5
+ In den Jahren 1900-1901 geschahen viele Überfälle von O`Reillys.
6
+ </para>
7
+ </chapter>
@@ -0,0 +1,55 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'minitest/spec'
3
+ require 'minitest/autorun'
4
+ require "docbook_status"
5
+
6
+ describe DocbookStatus do
7
+ it "works" do
8
+ true
9
+ end
10
+
11
+ it "complains if the input is not DocBook 5" do
12
+ non5 = XML::Document.string '<?xml version="1.0"?><article/>'
13
+ dbs = DocbookStatus.new()
14
+ status = dbs.is_docbook?(non5)
15
+ status.must_be :==, false
16
+ end
17
+
18
+ it "input is DocBook 5" do
19
+ non5 = XML::Document.string '<?xml version="1.0"?><article xmlns="http://docbook.org/ns/docbook"/>'
20
+ dbs = DocbookStatus.new()
21
+ status = dbs.is_docbook?(non5)
22
+ status.must_be :==, true
23
+ end
24
+
25
+ it "counts correctly" do
26
+ input = <<EOI
27
+ <?xml version="1.0" ?>
28
+ <article xmlns="http://docbook.org/ns/docbook" version="5.0">
29
+ <title>A1</title>
30
+ <section>
31
+ <title>S1</title>
32
+ <para>
33
+ Dies ist ein Test .. Dies ist ein Test.
34
+ In den Jahren 1900-1901 geschahen viele Überfälle von O`Reillys.
35
+ </para>
36
+ </section>
37
+ </article>
38
+ EOI
39
+ dbs = DocbookStatus.new()
40
+ ind = XML::Document.string(input)
41
+ sections = dbs.analyze_document(ind)
42
+ sections.must_equal([['A1', 17, 0, 'article'],['S1', 17, 1, 'section']])
43
+ end
44
+
45
+ it "processes includes" do
46
+ dbs = DocbookStatus.new()
47
+ ind = XML::Document.file('test/fixtures/book.xml')
48
+ if (dbs.has_xinclude?(ind))
49
+ ind.xinclude
50
+ end
51
+ sections = dbs.analyze_document(ind)
52
+ sections.must_equal([['B1', 34, 0, 'book'],['C1', 17, 1, 'chapter'],['C2', 17, 1, 'chapter']])
53
+ end
54
+
55
+ end
data/version.txt ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: docbook_status
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Rainer Volz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-08 00:00:00.000000000 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: bones
17
+ requirement: &2169388760 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 3.7.1
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *2169388760
26
+ description: A utility for DocBook authors/publishers showing the document structure
27
+ (sections) and word count of a DocBook project. It is intended to provide an overview
28
+ of a DocBook project's structure and volume while you are writing or editing it.
29
+ email: dev@textmulch.de
30
+ executables:
31
+ - docbook_status
32
+ extensions: []
33
+ extra_rdoc_files:
34
+ - History.txt
35
+ - README.txt
36
+ - bin/docbook_status
37
+ files:
38
+ - .bnsignore
39
+ - Gemfile
40
+ - Gemfile.lock
41
+ - History.txt
42
+ - README.txt
43
+ - Rakefile
44
+ - bin/docbook_status
45
+ - docbook_status.gemspec
46
+ - lib/docbook_status.rb
47
+ - spec/docbook_status_spec.rb
48
+ - spec/spec_helper.rb
49
+ - test/fixtures/book.xml
50
+ - test/fixtures/chapter2.xml
51
+ - test/test_docbook_status.rb
52
+ - version.txt
53
+ has_rdoc: true
54
+ homepage: http://projekte.textmuch.de/docbook_status/
55
+ licenses: []
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --main
59
+ - README.txt
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project: docbook_status
76
+ rubygems_version: 1.6.2
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: A utility for DocBook authors/publishers showing the document structure (sections)
80
+ and word count of a DocBook project.
81
+ test_files:
82
+ - test/test_docbook_status.rb