erlapi 0.1.9

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.
Files changed (100) hide show
  1. data/.document +5 -0
  2. data/.gitignore +5 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +15 -0
  5. data/Rakefile +56 -0
  6. data/VERSION +1 -0
  7. data/bin/erlapi +26 -0
  8. data/erlapi.gemspec +140 -0
  9. data/lib/erlapi.rb +38 -0
  10. data/lib/erlapi/generator.rb +194 -0
  11. data/lib/erlapi/generator/shtml.rb +353 -0
  12. data/lib/erlapi/generator/template/direct/_context.rhtml +172 -0
  13. data/lib/erlapi/generator/template/direct/class.rhtml +40 -0
  14. data/lib/erlapi/generator/template/direct/file.rhtml +30 -0
  15. data/lib/erlapi/generator/template/direct/index.rhtml +14 -0
  16. data/lib/erlapi/generator/template/direct/resources/apple-touch-icon.png +0 -0
  17. data/lib/erlapi/generator/template/direct/resources/css/main.css +263 -0
  18. data/lib/erlapi/generator/template/direct/resources/css/panel.css +383 -0
  19. data/lib/erlapi/generator/template/direct/resources/css/reset.css +53 -0
  20. data/lib/erlapi/generator/template/direct/resources/favicon.ico +0 -0
  21. data/lib/erlapi/generator/template/direct/resources/i/arrows.png +0 -0
  22. data/lib/erlapi/generator/template/direct/resources/i/results_bg.png +0 -0
  23. data/lib/erlapi/generator/template/direct/resources/i/tree_bg.png +0 -0
  24. data/lib/erlapi/generator/template/direct/resources/js/jquery-1.3.2.min.js +19 -0
  25. data/lib/erlapi/generator/template/direct/resources/js/jquery-effect.js +593 -0
  26. data/lib/erlapi/generator/template/direct/resources/js/main.js +22 -0
  27. data/lib/erlapi/generator/template/direct/resources/js/searchdoc.js +628 -0
  28. data/lib/erlapi/generator/template/direct/resources/panel/index.html +71 -0
  29. data/lib/erlapi/generator/template/merge/index.rhtml +14 -0
  30. data/lib/erlapi/generator/template/shtml/_context.rhtml +164 -0
  31. data/lib/erlapi/generator/template/shtml/class.rhtml +46 -0
  32. data/lib/erlapi/generator/template/shtml/file.rhtml +37 -0
  33. data/lib/erlapi/generator/template/shtml/index.rhtml +14 -0
  34. data/lib/erlapi/generator/template/shtml/resources/apple-touch-icon.png +0 -0
  35. data/lib/erlapi/generator/template/shtml/resources/css/main.css +191 -0
  36. data/lib/erlapi/generator/template/shtml/resources/css/panel.css +383 -0
  37. data/lib/erlapi/generator/template/shtml/resources/css/reset.css +53 -0
  38. data/lib/erlapi/generator/template/shtml/resources/favicon.ico +0 -0
  39. data/lib/erlapi/generator/template/shtml/resources/i/arrows.png +0 -0
  40. data/lib/erlapi/generator/template/shtml/resources/i/results_bg.png +0 -0
  41. data/lib/erlapi/generator/template/shtml/resources/i/tree_bg.png +0 -0
  42. data/lib/erlapi/generator/template/shtml/resources/js/jquery-1.3.2.min.js +19 -0
  43. data/lib/erlapi/generator/template/shtml/resources/js/main.js +34 -0
  44. data/lib/erlapi/generator/template/shtml/resources/js/searchdoc.js +628 -0
  45. data/lib/erlapi/generator/template/shtml/resources/panel/index.html +71 -0
  46. data/lib/erlapi/helpers.rb +26 -0
  47. data/lib/erlapi/merge.rb +217 -0
  48. data/lib/erlapi/parser.rb +134 -0
  49. data/lib/erlapi/shtml.rb +351 -0
  50. data/lib/erlapi/templatable.rb +51 -0
  51. data/lib/erlapi/templates/html/direct/_context.rhtml +172 -0
  52. data/lib/erlapi/templates/html/direct/class.rhtml +40 -0
  53. data/lib/erlapi/templates/html/direct/file.rhtml +30 -0
  54. data/lib/erlapi/templates/html/direct/index.rhtml +14 -0
  55. data/lib/erlapi/templates/html/direct/resources/apple-touch-icon.png +0 -0
  56. data/lib/erlapi/templates/html/direct/resources/css/main.css +263 -0
  57. data/lib/erlapi/templates/html/direct/resources/css/panel.css +383 -0
  58. data/lib/erlapi/templates/html/direct/resources/css/reset.css +53 -0
  59. data/lib/erlapi/templates/html/direct/resources/favicon.ico +0 -0
  60. data/lib/erlapi/templates/html/direct/resources/i/arrows.png +0 -0
  61. data/lib/erlapi/templates/html/direct/resources/i/results_bg.png +0 -0
  62. data/lib/erlapi/templates/html/direct/resources/i/tree_bg.png +0 -0
  63. data/lib/erlapi/templates/html/direct/resources/js/jquery-1.3.2.min.js +19 -0
  64. data/lib/erlapi/templates/html/direct/resources/js/jquery-effect.js +593 -0
  65. data/lib/erlapi/templates/html/direct/resources/js/main.js +22 -0
  66. data/lib/erlapi/templates/html/direct/resources/js/searchdoc.js +628 -0
  67. data/lib/erlapi/templates/html/direct/resources/panel/index.html +71 -0
  68. data/lib/erlapi/templates/html/merge/index.rhtml +14 -0
  69. data/lib/erlapi/templates/html/shtml/_context.rhtml +68 -0
  70. data/lib/erlapi/templates/html/shtml/class.rhtml +25 -0
  71. data/lib/erlapi/templates/html/shtml/file.rhtml +37 -0
  72. data/lib/erlapi/templates/html/shtml/index.rhtml +14 -0
  73. data/lib/erlapi/templates/html/shtml/resources copy/apple-touch-icon.png +0 -0
  74. data/lib/erlapi/templates/html/shtml/resources copy/css/main.css +195 -0
  75. data/lib/erlapi/templates/html/shtml/resources copy/css/panel.css +383 -0
  76. data/lib/erlapi/templates/html/shtml/resources copy/css/reset.css +53 -0
  77. data/lib/erlapi/templates/html/shtml/resources copy/favicon.ico +0 -0
  78. data/lib/erlapi/templates/html/shtml/resources copy/i/arrows.png +0 -0
  79. data/lib/erlapi/templates/html/shtml/resources copy/i/results_bg.png +0 -0
  80. data/lib/erlapi/templates/html/shtml/resources copy/i/tree_bg.png +0 -0
  81. data/lib/erlapi/templates/html/shtml/resources copy/js/jquery-1.3.2.min.js +19 -0
  82. data/lib/erlapi/templates/html/shtml/resources copy/js/main.js +34 -0
  83. data/lib/erlapi/templates/html/shtml/resources copy/js/searchdoc.js +628 -0
  84. data/lib/erlapi/templates/html/shtml/resources copy/panel/index.html +71 -0
  85. data/lib/erlapi/templates/html/shtml/resources/apple-touch-icon.png +0 -0
  86. data/lib/erlapi/templates/html/shtml/resources/css/main.css +263 -0
  87. data/lib/erlapi/templates/html/shtml/resources/css/panel.css +383 -0
  88. data/lib/erlapi/templates/html/shtml/resources/css/reset.css +53 -0
  89. data/lib/erlapi/templates/html/shtml/resources/favicon.ico +0 -0
  90. data/lib/erlapi/templates/html/shtml/resources/i/arrows.png +0 -0
  91. data/lib/erlapi/templates/html/shtml/resources/i/results_bg.png +0 -0
  92. data/lib/erlapi/templates/html/shtml/resources/i/tree_bg.png +0 -0
  93. data/lib/erlapi/templates/html/shtml/resources/js/jquery-1.3.2.min.js +19 -0
  94. data/lib/erlapi/templates/html/shtml/resources/js/jquery-effect.js +593 -0
  95. data/lib/erlapi/templates/html/shtml/resources/js/main.js +22 -0
  96. data/lib/erlapi/templates/html/shtml/resources/js/searchdoc.js +620 -0
  97. data/lib/erlapi/templates/html/shtml/resources/panel/index.html +71 -0
  98. data/test/erlapi_test.rb +7 -0
  99. data/test/test_helper.rb +10 -0
  100. metadata +155 -0
@@ -0,0 +1,71 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
3
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
4
+
5
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
6
+ <head>
7
+ <title>layout</title>
8
+ <link rel="stylesheet" href="../css/reset.css" type="text/css" media="screen" charset="utf-8" />
9
+ <link rel="stylesheet" href="../css/panel.css" type="text/css" media="screen" charset="utf-8" />
10
+ <script src="search_index.js" type="text/javascript" charset="utf-8"></script>
11
+ <script src="tree.js" type="text/javascript" charset="utf-8"></script>
12
+ <script src="../js/jquery-1.3.2.min.js" type="text/javascript" charset="utf-8"></script>
13
+ <script src="../js/searchdoc.js" type="text/javascript" charset="utf-8"></script>
14
+ <script type="text/javascript" charset="utf-8">
15
+ //<![CDATA[
16
+ function placeholder() {
17
+ if (jQuery.browser.safari) return;
18
+ $('#search-label').click(function() {
19
+ $('#search').focus();
20
+ $('#search-label').hide();
21
+ });
22
+
23
+ $('#search').focus(function() {
24
+ $('#search-label').hide();
25
+ });
26
+ $('#search').blur(function() {
27
+ this.value == '' && $('#search-label').show()
28
+ });
29
+
30
+ $('#search')[0].value == '' && $('#search-label').show();
31
+ }
32
+ $(function() {
33
+ placeholder();
34
+ var panel = new Searchdoc.Panel($('#panel'), search_data, tree, top.frames[1]);
35
+ $('#search').focus();
36
+
37
+ var s = window.parent.location.search.match(/\?q=([^&]+)/);
38
+ if (s) {
39
+ s = decodeURIComponent(s[1]).replace(/\+/g, ' ');
40
+ if (s.length > 0)
41
+ {
42
+ $('#search').val(s);
43
+ panel.search(s, true);
44
+ }
45
+ }
46
+ })
47
+ //]]>
48
+ </script>
49
+ </head>
50
+ <body>
51
+ <div class="panel panel_tree" id="panel">
52
+ <div class="header">
53
+ <div>
54
+ <label for="search" id="search-label" style="display: none">Search</label>
55
+ <table>
56
+ <tr><td>
57
+ <input type="Search" placeholder="Search" autosave="searchdoc" results="10" id="search" autocomplete="off"/>
58
+ </td></tr>
59
+ </table></div>
60
+ </div>
61
+ <div class="tree">
62
+ <ul>
63
+ </ul>
64
+ </div>
65
+ <div class="result">
66
+ <ul>
67
+ </ul>
68
+ </div>
69
+ </div>
70
+ </body>
71
+ </html>
@@ -0,0 +1,26 @@
1
+ module Erlapi::Helpers
2
+ def each_letter_group(methods, &block)
3
+ group = {:name => '', :methods => []}
4
+ methods.sort{ |a, b| a.name <=> b.name }.each do |method|
5
+ gname = group_name method.name
6
+ if gname != group[:name]
7
+ yield group unless group[:methods].size == 0
8
+ group = {
9
+ :name => gname,
10
+ :methods => []
11
+ }
12
+ end
13
+ group[:methods].push(method)
14
+ end
15
+ yield group unless group[:methods].size == 0
16
+ end
17
+
18
+ protected
19
+ def group_name name
20
+ if match = name.match(/^([a-z])/i)
21
+ match[1].upcase
22
+ else
23
+ '#'
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,217 @@
1
+ require 'optparse'
2
+ require 'pathname'
3
+ require 'fileutils'
4
+ require 'json'
5
+
6
+ require 'sdoc/templatable'
7
+
8
+ class SDoc::Merge
9
+ include SDoc::Templatable
10
+
11
+ FLAG_FILE = "created.rid"
12
+
13
+ def initialize()
14
+ @names = []
15
+ @urls = []
16
+ @op_dir = 'doc'
17
+ @title = ''
18
+ @directories = []
19
+ template_dir = RDoc::Generator::SHtml.template_dir('merge')
20
+ @template_dir = Pathname.new File.expand_path(template_dir)
21
+ end
22
+
23
+ def merge(options)
24
+ parse_options options
25
+
26
+ @outputdir = Pathname.new( @op_dir )
27
+
28
+ check_directories
29
+ setup_output_dir
30
+ setup_names
31
+ copy_files
32
+ copy_docs if @urls.empty?
33
+ merge_search_index
34
+ merge_tree
35
+ generate_index_file
36
+ end
37
+
38
+ def parse_options(options)
39
+ opts = OptionParser.new do |opt|
40
+ opt.banner = "Usage: sdoc-merge [options] directories"
41
+
42
+ opt.on("-n", "--names [NAMES]", "Names of merged repositories. Comma separated") do |v|
43
+ @names = v.split(',').map{|name| name.strip }
44
+ end
45
+
46
+ opt.on("-o", "--op [DIRECTORY]", "Set the output directory") do |v|
47
+ @op_dir = v
48
+ end
49
+
50
+ opt.on("-t", "--title [TITLE]", "Set the title of merged file") do |v|
51
+ @title = v
52
+ end
53
+
54
+ opt.on("-u", "--urls [URLS]", "Paths to merged docs. If you \n" +
55
+ "set this files and classes won't be actualy copied to merged build") do |v|
56
+ @urls = v.split(' ').map{|name| name.strip }
57
+ end
58
+ end
59
+ opts.parse! options
60
+ @directories = options.dup
61
+ end
62
+
63
+ def merge_tree
64
+ tree = []
65
+ @directories.each_with_index do |dir, i|
66
+ name = @names[i]
67
+ url = @urls.empty? ? name : @urls[i]
68
+ filename = File.join dir, RDoc::Generator::SHtml::TREE_FILE
69
+ data = open(filename).read.sub(/var tree =\s*/, '')
70
+ subtree = JSON.parse data, :max_nesting => 35
71
+ item = [
72
+ name,
73
+ url + '/' + extract_index_path(dir),
74
+ '',
75
+ append_path(subtree, url)
76
+ ]
77
+ tree << item
78
+ end
79
+
80
+ dst = File.join @op_dir, RDoc::Generator::SHtml::TREE_FILE
81
+ FileUtils.mkdir_p File.dirname(dst)
82
+ File.open(dst, "w", 0644) do |f|
83
+ f.write('var tree = '); f.write(tree.to_json)
84
+ end
85
+ end
86
+
87
+ def append_path subtree, path
88
+ subtree.map do |item|
89
+ item[1] = path + '/' + item[1] unless item[1].empty?
90
+ item[3] = append_path item[3], path
91
+ item
92
+ end
93
+ end
94
+
95
+ def merge_search_index
96
+ items = []
97
+ @indexes = {}
98
+ @directories.each_with_index do |dir, i|
99
+ name = @names[i]
100
+ url = @urls.empty? ? name : @urls[i]
101
+ filename = File.join dir, RDoc::Generator::SHtml::SEARCH_INDEX_FILE
102
+ data = open(filename).read.sub(/var search_data =\s*/, '')
103
+ subindex = JSON.parse data, :max_nesting => 35
104
+ @indexes[name] = subindex
105
+
106
+ searchIndex = subindex["index"]["searchIndex"]
107
+ longSearchIndex = subindex["index"]["longSearchIndex"]
108
+ subindex["index"]["info"].each_with_index do |info, j|
109
+ info[2] = url + '/' + info[2]
110
+ info[6] = i
111
+ items << {
112
+ :info => info,
113
+ :searchIndex => searchIndex[j],
114
+ :longSearchIndex => name + ' ' + longSearchIndex[j]
115
+ }
116
+ end
117
+ end
118
+ items.sort! do |a, b|
119
+ # type (class/method/file) or name or doc part or namespace
120
+ [a[:info][5], a[:info][0], a[:info][6], a[:info][1]] <=> [b[:info][5], b[:info][0], b[:info][6], b[:info][1]]
121
+ end
122
+
123
+ index = {
124
+ :searchIndex => items.map{|item| item[:searchIndex]},
125
+ :longSearchIndex => items.map{|item| item[:longSearchIndex]},
126
+ :info => items.map{|item| item[:info]}
127
+ }
128
+ search_data = {
129
+ :index => index,
130
+ :badges => @names
131
+ }
132
+
133
+ dst = File.join @op_dir, RDoc::Generator::SHtml::SEARCH_INDEX_FILE
134
+ FileUtils.mkdir_p File.dirname(dst)
135
+ File.open(dst, "w", 0644) do |f|
136
+ f.write('var search_data = '); f.write(search_data.to_json)
137
+ end
138
+ end
139
+
140
+ def extract_index_path dir
141
+ filename = File.join dir, 'index.html'
142
+ content = File.open(filename) { |f| f.read }
143
+ match = content.match(/<frame\s+src="([^"]+)"\s+name="docwin"/mi)
144
+ if match
145
+ match[1]
146
+ else
147
+ ''
148
+ end
149
+ end
150
+
151
+ def generate_index_file
152
+ templatefile = @template_dir + 'index.rhtml'
153
+ outfile = @outputdir + 'index.html'
154
+ url = @urls.empty? ? @names[0] : @urls[0]
155
+ index_path = url + '/' + extract_index_path(@directories[0])
156
+
157
+ render_template templatefile, binding(), outfile
158
+ end
159
+
160
+ def setup_names
161
+ unless @names.size > 0
162
+ @directories.each do |dir|
163
+ name = File.basename dir
164
+ name = File.basename File.dirname(dir) if name == 'doc'
165
+ @names << name
166
+ end
167
+ end
168
+ end
169
+
170
+ def copy_docs
171
+ @directories.each_with_index do |dir, i|
172
+ name = @names[i]
173
+ index_dir = File.dirname(RDoc::Generator::SHtml::TREE_FILE)
174
+ FileUtils.mkdir_p(File.join(@op_dir, name))
175
+
176
+ Dir.new(dir).each do |item|
177
+ if File.directory?(File.join(dir, item)) && item != '.' && item != '..' && item != index_dir
178
+ FileUtils.cp_r File.join(dir, item), File.join(@op_dir, name, item), :preserve => true
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ def copy_files
185
+ dir = @directories.first
186
+ Dir.new(dir).each do |item|
187
+ if item != '.' && item != '..' && item != RDoc::Generator::SHtml::FILE_DIR && item != RDoc::Generator::SHtml::CLASS_DIR
188
+ FileUtils.cp_r File.join(dir, item), @op_dir, :preserve => true
189
+ end
190
+ end
191
+ end
192
+
193
+ def setup_output_dir
194
+ if File.exists? @op_dir
195
+ error "#{@op_dir} allready exists"
196
+ end
197
+ FileUtils.mkdir_p @op_dir
198
+ end
199
+
200
+ def check_directories
201
+ @directories.each do |dir|
202
+ unless File.exists?(File.join(dir, FLAG_FILE)) &&
203
+ File.exists?(File.join(dir, RDoc::Generator::SHtml::TREE_FILE)) &&
204
+ File.exists?(File.join(dir, RDoc::Generator::SHtml::SEARCH_INDEX_FILE))
205
+ error "#{dir} does not seem to be an sdoc directory"
206
+ end
207
+ end
208
+ end
209
+
210
+ ##
211
+ # Report an error message and exit
212
+
213
+ def error(msg)
214
+ raise RDoc::Error, msg
215
+ end
216
+
217
+ end
@@ -0,0 +1,134 @@
1
+ require 'nokogiri'
2
+
3
+ module Erlapi::Parser
4
+ class Base
5
+ attr_accessor :src_dir, :template_dir, :files, :modules, :entities_coder
6
+ def initialize(src_dir = nil)
7
+ self.files = []
8
+ self.modules = {}
9
+ self.src_dir = Pathname.new(src_dir || File.join(File.dirname(__FILE__), '..', 'src'))
10
+ self.template_dir = File.join(File.dirname(__FILE__), 'templates')
11
+ end
12
+
13
+ def parse
14
+ files.each do |file|
15
+ puts "Parsing #{file}"
16
+ doc = Nokogiri::XML(File.read(file))
17
+
18
+ mod = Erlapi::Parser::Module.new(self, doc)
19
+ self.modules[mod.title] = mod if mod.valid
20
+ end
21
+ end
22
+
23
+ def inner_xml(node)
24
+ node.is_a?(Nokogiri::XML::NodeSet) ? node.collect{|j| j.children.to_xml}.join('') : node.children.to_xml
25
+ end
26
+
27
+ def special_tags(str)
28
+ str.gsub!(/<c>(.*?)<\/c>/mi, '<tt>\1</tt>')
29
+ str.gsub!(/<code.*?>(.*?)<\/code>/mi, '<pre>\1</pre>')
30
+ str.gsub!(/<v.*?>(.*?)<\/v>/mi, '<b>\1</b><br/>')
31
+ str.gsub!(/<input.*?>(.*?)<\/input>/mi, '<tt>\1</tt><br/>')
32
+ str
33
+ end
34
+
35
+ def prepare_string(str)
36
+ str.gsub(/\\\\/, '\\')
37
+ end
38
+
39
+ def files
40
+ load_files(src_dir.realpath)
41
+ @files
42
+ end
43
+
44
+ def load_files(dir_path)
45
+ dir = Dir.new(dir_path)
46
+ dir.each do |file_name|
47
+ full_path = File.join(dir.path, file_name)
48
+ if file_name != '.' && file_name != '..'
49
+ if File.directory?(full_path)
50
+ load_files(full_path)
51
+ else
52
+ @files << full_path if File.extname(file_name) == '.xml'
53
+ end
54
+ end
55
+ end
56
+ dir.close
57
+ end
58
+
59
+ end
60
+
61
+ class Module
62
+ attr_accessor :parser, :title, :summary, :desc, :datatypes, :funcs, :sections, :valid, :doc
63
+ def initialize(parser, doc)
64
+ self.doc = doc
65
+ self.parser = parser
66
+ self.title = doc.css('module').inner_html
67
+ self.summary = doc.css('modulesummary').inner_html || ''
68
+ if self.title && self.title != ''
69
+ self.valid = true
70
+ else
71
+ self.valid = false
72
+ end
73
+ if valid
74
+ define_desc
75
+ define_sections
76
+ define_funcs
77
+ end
78
+ end
79
+
80
+ def define_desc
81
+ self.desc = self.parser.special_tags(self.parser.inner_xml(doc.css('description')))
82
+ end
83
+
84
+ def define_sections
85
+ self.sections = []
86
+ doc.css('section').each do |node|
87
+ self.sections << Erlapi::Parser::Section.new(self, node)
88
+ end
89
+ end
90
+
91
+ def define_funcs
92
+ self.funcs = []
93
+ doc.css('funcs func').each do |node|
94
+ func = Erlapi::Parser::Func.new(self, node)
95
+ self.funcs << func if func.short_name
96
+ end
97
+ end
98
+ end
99
+
100
+ class Func
101
+ attr_accessor :p_module, :short_name, :names, :summary, :types, :desc, :ref, :short_names
102
+
103
+ def initialize(p_module, node)
104
+ self.p_module = p_module
105
+ self.names = node.css('name').map {|v| v.inner_html}
106
+ if self.names
107
+ self.short_names = self.names.map { |n| n.match(/([\w\d_-]*)\(/) ? $~[1] : nil }.compact.uniq
108
+ self.short_name = self.short_names.first if self.short_names
109
+ end
110
+ self.ref = self.names.first.gsub(/[^\w]/, '')
111
+ self.summary = parser.inner_xml(node.css('fsummary'))
112
+ self.types = parser.special_tags(parser.inner_xml(node.css('type')))
113
+ self.desc = parser.special_tags(parser.inner_xml(node.css('desc')))
114
+ end
115
+
116
+ def parser
117
+ self.p_module.parser
118
+ end
119
+ end
120
+
121
+ class Section
122
+ attr_accessor :p_module, :name, :desc
123
+
124
+ def initialize(p_module, node)
125
+ self.p_module = p_module
126
+ self.name = node.css('title').inner_html
127
+ self.desc = parser.special_tags(parser.inner_xml(node))
128
+ end
129
+
130
+ def parser
131
+ self.p_module.parser
132
+ end
133
+ end
134
+ end