gren 0.2.4 → 0.3.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.
@@ -0,0 +1,35 @@
1
+ # -*- mode: ruby; coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief gren web検索
5
+ # @author ongaeshi
6
+ # @date 2010/10/13
7
+
8
+ require 'rubygems'
9
+ require 'rack'
10
+ require File.join(File.dirname(__FILE__), 'home')
11
+ require File.join(File.dirname(__FILE__), 'searcher')
12
+ require File.join(File.dirname(__FILE__), 'viewer')
13
+ require File.join(File.dirname(__FILE__), 'help')
14
+
15
+ use Rack::CommonLogger
16
+ use Rack::Runtime
17
+ use Rack::Static, :urls => ["/css", "/images"], :root => "public"
18
+ use Rack::ContentLength
19
+
20
+ map '/' do
21
+ run Grenweb::Home.new
22
+ end
23
+
24
+ map '/::search' do
25
+ run Grenweb::Searcher.new
26
+ end
27
+
28
+ map '/::view' do
29
+ run Grenweb::Viewer.new
30
+ end
31
+
32
+ map '/::help' do
33
+ run Grenweb::Help.new
34
+ end
35
+
@@ -0,0 +1,52 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief grenwebで使用する行指向の検索
5
+ # @author ongaeshi
6
+ # @date 2010/10/18
7
+
8
+ module Grenweb
9
+ class Grep
10
+ attr_reader :content
11
+
12
+ def initialize(content)
13
+ @content = content.split("\n")
14
+ end
15
+
16
+ MatchLineResult = Struct.new(:index, :match_datas)
17
+
18
+ def match_lines_or(patterns)
19
+ result = []
20
+ patternRegexps = strs2regs(patterns, true) # @todo ignoreオプションを付ける
21
+
22
+ @content.each_with_index do |line, index|
23
+ match_datas = []
24
+ patternRegexps.each {|v| match_datas << v.match(line)}
25
+
26
+ if (match_datas.any?)
27
+ result << MatchLineResult.new(index, match_datas)
28
+ end
29
+ end
30
+
31
+ result
32
+ end
33
+
34
+ def context(result, num)
35
+ end
36
+
37
+ private
38
+
39
+ def strs2regs(strs, ignore = false)
40
+ regs = []
41
+
42
+ strs.each do |v|
43
+ option = 0
44
+ option |= Regexp::IGNORECASE if (ignore)
45
+ regs << Regexp.new(v, option)
46
+ end
47
+
48
+ regs
49
+ end
50
+ end
51
+ end
52
+
@@ -0,0 +1,37 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief ホーム画面
5
+ # @author ongaeshi
6
+ # @date 2010/10/13
7
+
8
+ require 'rack'
9
+ require File.join(File.dirname(__FILE__), 'database')
10
+ require File.join(File.dirname(__FILE__), 'html_renderer')
11
+ require File.join(File.dirname(__FILE__), 'query')
12
+
13
+ module Grenweb
14
+ class Help
15
+ include Rack::Utils
16
+
17
+ def call(env)
18
+ @request = Rack::Request.new(env)
19
+ @query = Query.new(@request)
20
+
21
+ @response = Rack::Response.new
22
+ @response["Content-Type"] = "text/html; charset=UTF-8"
23
+
24
+ render
25
+ end
26
+
27
+ private
28
+
29
+ def render
30
+ @response.write HTMLRendeler.header("gren - help", "gren - help")
31
+ @response.write HTMLRendeler.sample_code
32
+ @response.write HTMLRendeler.footer
33
+ @response.to_a
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,37 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief ホーム画面
5
+ # @author ongaeshi
6
+ # @date 2010/10/13
7
+
8
+ require 'rack'
9
+ require File.join(File.dirname(__FILE__), 'database')
10
+ require File.join(File.dirname(__FILE__), 'html_renderer')
11
+ require File.join(File.dirname(__FILE__), 'query')
12
+
13
+ module Grenweb
14
+ class Home
15
+ include Rack::Utils
16
+
17
+ def call(env)
18
+ @request = Rack::Request.new(env)
19
+ @query = Query.new(@request)
20
+
21
+ @response = Rack::Response.new
22
+ @response["Content-Type"] = "text/html; charset=UTF-8"
23
+
24
+ render
25
+ end
26
+
27
+ private
28
+
29
+ def render
30
+ @response.write HTMLRendeler.header_home("gren", "gren", Version)
31
+ @response.write HTMLRendeler.search_box
32
+ @response.write HTMLRendeler.footer_home("??", Database.instance.fileNum)
33
+ @response.to_a
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,231 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief HTMLの描画ルーチン
5
+ # @author ongaeshi
6
+ # @date 2010/10/17
7
+
8
+ require 'rubygems'
9
+ require 'rack'
10
+ require File.join(File.dirname(__FILE__), 'grep')
11
+
12
+ module Grenweb
13
+ class HTMLRendeler
14
+ include Rack::Utils
15
+
16
+ def self.header(title, header1)
17
+ <<EOS
18
+ <?xml version="1.0" encoding="utf-8"?>
19
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
20
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
21
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
22
+ <head>
23
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
24
+ <!-- <meta name="robot" content="noindex,nofollow" /> -->
25
+ <title>#{title}</title>
26
+ <link rel="stylesheet" href="/css/gren.css" type="text/css" media="all" />
27
+ </head>
28
+ <body>
29
+ <div class="header">
30
+ <h1>
31
+ <a href="/"><img src="/images/gren-icon-mini.png" alt="gren-icon" border="0"/></a>
32
+ #{header1}
33
+ </h1>
34
+ </div>
35
+
36
+ <div class="content">
37
+ EOS
38
+ end
39
+
40
+ def self.footer
41
+ <<EOS
42
+ </div>
43
+
44
+ <div class="footer">
45
+ </div>
46
+ </body>
47
+ </html>
48
+ EOS
49
+ end
50
+
51
+ def self.header_home(title, header1, version)
52
+ <<EOS
53
+ <?xml version="1.0" encoding="utf-8"?>
54
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
55
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
56
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
57
+ <head>
58
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
59
+ <!-- <meta name="robot" content="noindex,nofollow" /> -->
60
+ <title>#{title}</title>
61
+ <link rel="stylesheet" href="/css/gren.css" type="text/css" media="all" />
62
+ </head>
63
+ <body>
64
+ <div align="center">
65
+ <div class="header_home">
66
+ <h1>
67
+ <a href="/"><img src="/images/gren-icon.png" alt="gren-icon" border="0" height="100px"/></a>
68
+ #{header1} <font class="version">#{version}</font>
69
+ </h1>
70
+ </div>
71
+
72
+ <div class="content">
73
+ EOS
74
+ end
75
+
76
+ def self.footer_home(package, files)
77
+ <<EOS
78
+ </div>
79
+
80
+ <div class="footer_home">
81
+ <!-- <a href="/::search/p:*">#{package}</a>のパッケージ , -->
82
+ <a href="/::search/f:*">#{files}</a>のファイル<br>
83
+ <a href="/::help">ヘルプ</a> ,
84
+ <a href="http://ongaeshi.github.com/gren">grenについて</a>
85
+ </div>
86
+ </div>
87
+ </body>
88
+ </html>
89
+ EOS
90
+ end
91
+
92
+ def self.result_record(record, patterns, nth=1)
93
+ if (patterns.size > 0)
94
+ <<EOS
95
+ <dt class='result-record'><a href='#{"/::view/" + Rack::Utils::escape_html(record.shortpath)}'>#{record.shortpath}</a></dt>
96
+ <dd>
97
+ <pre class='lines'>
98
+ #{result_record_match_line(record, patterns, nth)}
99
+ </pre>
100
+ </dd>
101
+ EOS
102
+ else
103
+ <<EOS
104
+ <dt class='result-record'><a href='#{"/::view/" + Rack::Utils::escape_html(record.shortpath)}'>#{record.shortpath}</a></dt>
105
+ EOS
106
+ end
107
+ end
108
+
109
+ def self.result_record_match_line(record, patterns, nth)
110
+ str = ""
111
+
112
+ grep = Grep.new(record.content)
113
+ lines = grep.match_lines_or(patterns)
114
+
115
+ unless (lines.empty?)
116
+ index = lines[0].index
117
+
118
+ (index - nth..index + nth).each do |i|
119
+ if (0 <= i && i < grep.content.size)
120
+ match_datas = (i == index) ? lines[0].match_datas : []
121
+ str << line(i + 1, grep.content[i], match_datas) + "\n"
122
+ end
123
+ end
124
+ end
125
+
126
+ str
127
+ end
128
+
129
+ def self.record_content(record)
130
+ <<EOS
131
+ <pre>
132
+ #{record_content_line(record)}
133
+ </pre>
134
+ EOS
135
+ end
136
+
137
+ def self.record_content_line(record)
138
+ str = ""
139
+
140
+ grep = Grep.new(record.content)
141
+ grep.content.each_with_index do |l, index|
142
+ str << line(index + 1, l, []) + "\n"
143
+ end
144
+
145
+ str
146
+ end
147
+
148
+ def self.line(lineno, line, match_datas)
149
+ sprintf("%5d: %s", lineno, match_strong(Rack::Utils::escape_html(line), match_datas))
150
+ end
151
+
152
+ def self.match_strong(line, match_datas)
153
+ match_datas.each do |m|
154
+ line = line.split(m[0]).join('<strong>' + m[0] + '</strong>') unless (m.nil?)
155
+ end
156
+
157
+ line
158
+ end
159
+
160
+ def self.pagination_link(page, label)
161
+ href = "?page=#{page}"
162
+ pagination_span("<a href='#{href}'>#{label}</a>")
163
+ end
164
+
165
+ def self.pagination_span(content)
166
+ "<span class='pagination-link'>#{content}</span>\n"
167
+ end
168
+
169
+ def self.empty_summary()
170
+ <<EOS
171
+ <div class='search-summary'>
172
+ <p>gren web検索</p>
173
+ </div>
174
+ EOS
175
+ end
176
+
177
+ def self.search_summary(keyword, total_records, range, elapsed)
178
+ <<EOS
179
+ <div class='search-summary'>
180
+ <span class="keyword">#{keyword}</span>の検索結果:
181
+ <span class="total-entries">#{total_records}</span>件中
182
+ <span class="display-range">#{range.first} - #{range.last}</span>件(#{elapsed}秒)
183
+ </div>
184
+ EOS
185
+ end
186
+
187
+ def self.view_summary(path, elapsed)
188
+ <<EOS
189
+ <div class='search-summary'>
190
+ <span class="keyword">#{path}</span>(#{elapsed}秒)
191
+ </div>
192
+ EOS
193
+ end
194
+
195
+ def self.search_box(text = "")
196
+ <<EOS
197
+ <form method="post" action="/::search">
198
+ <p>
199
+ <input name="query" type="text" size="60" value="#{text}" />
200
+ <input type="submit" value="検索" />
201
+ </p>
202
+ </form>
203
+ EOS
204
+ end
205
+
206
+ def self.sample_code
207
+ <<EOS
208
+ <div class='sample-code'>
209
+ <ol>
210
+ <li>キーワードで検索<br>
211
+ #{link('def open')}
212
+ <li>1フレーズとして検索<br>
213
+ #{link('"def open"')}
214
+ <li>パッケージ名で絞り込み<br>
215
+ #{link('def open p:gren')}
216
+ <li>ファイル名や拡張子で絞り込み<br>
217
+ #{link('def open f:test s:rb')}
218
+ <li>組み合わせ<br>
219
+ #{link('p:gren p:tidtools s:rb f:test assert f:cli')}
220
+ </ol>
221
+ </div>
222
+ EOS
223
+ end
224
+
225
+ def self.link(keyword)
226
+ "<a href='/::search/#{Rack::Utils::escape_html(keyword)}'>#{keyword}</a>"
227
+ end
228
+ end
229
+ end
230
+
231
+
@@ -0,0 +1,63 @@
1
+ body {
2
+ }
3
+
4
+ div.header {
5
+ }
6
+
7
+ div.footer {
8
+ }
9
+
10
+ div.header_home {
11
+ font-size: 170%;
12
+ }
13
+
14
+ div.footer_home {
15
+ font-size: 85%;
16
+ margin-top: 3em;
17
+ }
18
+
19
+ div.search-summary {
20
+ border-color:#F4CA3F;
21
+ background-color:#FEFFF0;
22
+ border-top-style:solid;
23
+ border-top-width:1px;
24
+ border-bottom-style:solid;
25
+ border-bottom-width:1px;
26
+ margin-bottom:1em;
27
+ margin-top:1em;
28
+ padding-bottom:5px;
29
+ padding-top:5px;
30
+ padding-left:5px;
31
+ }
32
+
33
+ dt.result-record {
34
+ font-size: 105%;
35
+ }
36
+
37
+ pre.lines {
38
+ }
39
+
40
+ div.pagination {
41
+ background-color:#FEFFF0;
42
+ text-align: center;
43
+ margin-bottom: 20px;
44
+ }
45
+
46
+ pre {
47
+ border: 1px solid #dedede;
48
+ margin-bottom: 5px;
49
+ padding-left: 5px;
50
+ background-color: #fdfdfd;
51
+ font-weight: inherit;
52
+ margin-top: 5px;
53
+ padding-top: 5px;
54
+ padding-bottom: 5px;
55
+ }
56
+
57
+ span.keyword {
58
+ font-weight: bold;
59
+ }
60
+
61
+ font.version {
62
+ font-size: 35%;
63
+ }