gren 0.3.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +7 -0
  3. data/{History.ja.txt → HISTORY.ja.md} +41 -15
  4. data/HISTORY.md +92 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.ja.md +57 -0
  7. data/README.md +51 -0
  8. data/Rakefile +9 -39
  9. data/bin/gren +2 -7
  10. data/gren.gemspec +21 -0
  11. data/lib/gren.rb +3 -3
  12. data/lib/gren/cli.rb +13 -10
  13. data/lib/{common → gren/common}/grenfiletest.rb +0 -0
  14. data/lib/{common → gren/common}/grensnip.rb +1 -1
  15. data/lib/{common → gren/common}/platform.rb +0 -0
  16. data/lib/{common → gren/common}/string_snip.rb +0 -0
  17. data/lib/{common → gren/common}/util.rb +16 -10
  18. data/lib/{findgrep → gren/findgrep}/findgrep.rb +47 -143
  19. data/lib/{findgrep → gren/findgrep}/result.rb +1 -1
  20. data/lib/gren/version.rb +3 -0
  21. data/test/data/aaa.txt +1 -0
  22. data/test/data/abc.rb +8 -0
  23. data/test/data/bbb.txt +1 -0
  24. data/test/data/ccc.c +1 -0
  25. data/test/data/sub/ccc.txt +1 -0
  26. data/test/test_cli.rb +80 -0
  27. data/test/test_gren.rb +10 -10
  28. data/test/test_gren_util.rb +3 -2
  29. data/test/test_string_snip.rb +31 -31
  30. metadata +67 -177
  31. data/History.txt +0 -66
  32. data/Manifest.txt +0 -48
  33. data/PostInstall.txt +0 -7
  34. data/README.rdoc +0 -181
  35. data/bin/grendb +0 -11
  36. data/bin/grenweb +0 -11
  37. data/bin/mkgrendb +0 -11
  38. data/lib/common/display_util.rb +0 -62
  39. data/lib/grendb/cli.rb +0 -41
  40. data/lib/grenweb/cli.rb +0 -52
  41. data/lib/grenweb/database.rb +0 -179
  42. data/lib/grenweb/grenweb.ru +0 -35
  43. data/lib/grenweb/grep.rb +0 -52
  44. data/lib/grenweb/help.rb +0 -39
  45. data/lib/grenweb/home.rb +0 -39
  46. data/lib/grenweb/html_renderer.rb +0 -243
  47. data/lib/grenweb/public/css/gren.css +0 -63
  48. data/lib/grenweb/public/images/gren-icon-mini.png +0 -0
  49. data/lib/grenweb/public/images/gren-icon.png +0 -0
  50. data/lib/grenweb/query.rb +0 -82
  51. data/lib/grenweb/searcher.rb +0 -129
  52. data/lib/grenweb/viewer.rb +0 -51
  53. data/lib/mkgrendb/cli.rb +0 -49
  54. data/lib/mkgrendb/mkgrendb.rb +0 -230
  55. data/rake_rdoc_custom.rb +0 -13
  56. data/script/console +0 -10
  57. data/script/destroy +0 -14
  58. data/script/generate +0 -14
  59. data/test/test_grenweb_cli.rb +0 -10
  60. data/test/test_grenweb_html_renderer.rb +0 -41
  61. data/test/test_grenweb_query.rb +0 -54
  62. data/test/test_grenweb_searcher.rb +0 -35
@@ -1,52 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'optparse'
3
- require 'rubygems'
4
- require 'rack'
5
- require 'fileutils'
6
- require File.join(File.dirname(__FILE__), 'database')
7
- require 'launchy'
8
-
9
- module Grenweb
10
- class CLI
11
- def self.execute(stdout, arguments=[])
12
- option = {
13
- :Port => 9292,
14
- :DbFile => ENV['GRENDB_DEFAULT_DB'],
15
- }
16
-
17
- opt = OptionParser.new("#{File.basename($0)}")
18
- opt.on('--db [GREN_DB_FILE]', 'Search from the grendb database.') {|v| option[:DbFile] = v }
19
- opt.on('-p', '--port PORT', 'use PORT (default: 9292)') {|v| option[:Port] = v }
20
- opt.on('--no-browser', 'No launch browser.') {|v| option[:NoBrowser] = true }
21
- opt.parse!(arguments)
22
-
23
- # webサーバー起動
24
- stdout.puts <<EOF
25
- Start up grenweb !!
26
- URL : http://localhost:#{option[:Port]}
27
- DB : #{option[:DbFile]}
28
- ----------------------------------------
29
- EOF
30
-
31
- # 使用するデータベースの位置設定
32
- Database.setup(option[:DbFile])
33
-
34
- # サーバースクリプトのある場所へ移動
35
- FileUtils.cd(File.dirname(__FILE__))
36
-
37
- # ブラウザ起動
38
- Launchy.open("http://localhost:#{option[:Port]}") unless (option[:NoBrowser])
39
-
40
- # サーバー起動
41
- Rack::Server.start(
42
- :environment => "development",
43
- :pid => nil,
44
- :Port => option[:Port],
45
- :Host => "0.0.0.0",
46
- :AccessLog => [],
47
- :config => "grenweb.ru"
48
- )
49
-
50
- end
51
- end
52
- end
@@ -1,179 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # @file
4
- # @brief Grenwebで使用するデータベース
5
- # @author ongaeshi
6
- # @date 2010/10/17
7
-
8
- require 'groonga'
9
- require 'pathname'
10
- require 'singleton'
11
-
12
- module Grenweb
13
- class Database
14
- include Singleton
15
-
16
- def self.setup(dbFile)
17
- @@dbFile = dbFile
18
- end
19
-
20
- def initialize
21
- open(@@dbFile)
22
- end
23
-
24
- def open(dbFile)
25
- dbfile = Pathname(File.expand_path(dbFile))
26
-
27
- if dbfile.exist?
28
- Groonga::Database.open(dbfile.to_s)
29
- else
30
- raise "error : #{dbfile.to_s} not found!!"
31
- end
32
-
33
- @documents = Groonga::Context.default["documents"]
34
- end
35
-
36
- def record(shortpath)
37
- before = Time.now
38
- table = @documents.select { |record| record.shortpath == shortpath }
39
- elapsed = Time.now - before
40
- return table.records[0], elapsed
41
- end
42
-
43
- def fileNum
44
- @documents.select.size
45
- end
46
-
47
- def search(patterns, packages, fpaths, suffixs, page = 0, limit = -1)
48
- before = Time.now
49
-
50
- # 全てのパターンを検索
51
- if (fpaths.include?("*"))
52
- records, total_records = selectAll(page, limit)
53
- else
54
- records, total_records = searchMain(patterns, packages, fpaths, suffixs, page, limit)
55
- end
56
-
57
- # 検索にかかった時間
58
- elapsed = Time.now - before
59
-
60
- # 結果
61
- return records, total_records, elapsed
62
- end
63
-
64
- def selectAll(page, limit)
65
- table = @documents.select
66
-
67
- # マッチ数
68
- total_records = table.size
69
-
70
- # 2010/10/29 ongaeshi
71
- # 本当はこのようにgroongaAPIでソートしたいのだが上手くいかなかった
72
- # # ファイル名順にソート
73
- # records = table.sort([{:key => "shortpath", :order => "descending"}],
74
- # :offset => page * limit,
75
- # :limit => limit)
76
-
77
- # ソート
78
- records = table.records.sort_by{|record| record.shortpath.downcase }[page * limit, limit]
79
-
80
- return records, total_records
81
- end
82
-
83
- def searchMain(patterns, packages, fpaths, suffixs, page, limit)
84
- table = @documents.select do |record|
85
- expression = nil
86
-
87
- # キーワード
88
- patterns.each do |word|
89
- sub_expression = record.content =~ word
90
- if expression.nil?
91
- expression = sub_expression
92
- else
93
- expression &= sub_expression
94
- end
95
- end
96
-
97
- # パッケージ(OR)
98
- pe = package_expression(record, packages)
99
- if (pe)
100
- if expression.nil?
101
- expression = pe
102
- else
103
- expression &= pe
104
- end
105
- end
106
-
107
- # ファイルパス
108
- fpaths.each do |word|
109
- sub_expression = record.path =~ word
110
- if expression.nil?
111
- expression = sub_expression
112
- else
113
- expression &= sub_expression
114
- end
115
- end
116
-
117
- # 拡張子(OR)
118
- se = suffix_expression(record, suffixs)
119
- if (se)
120
- if expression.nil?
121
- expression = se
122
- else
123
- expression &= se
124
- end
125
- end
126
-
127
- # 検索式
128
- expression
129
- end
130
-
131
- # マッチ数
132
- total_records = table.size
133
-
134
- # スコアとタイムスタンプでソート
135
- records = table.sort([{:key => "_score", :order => "descending"},
136
- {:key => "timestamp", :order => "descending"}],
137
- :offset => page * limit,
138
- :limit => limit)
139
-
140
- return records, total_records
141
- end
142
- private :searchMain
143
-
144
- def package_expression(record, packages)
145
- sub = nil
146
-
147
- # @todo 専用カラム package が欲しいところ
148
- # でも今でもpackageはORとして機能してるからいいっちゃいい
149
- packages.each do |word|
150
- e = record.path =~ word
151
- if sub.nil?
152
- sub = e
153
- else
154
- sub |= e
155
- end
156
- end
157
-
158
- sub
159
- end
160
- private :package_expression
161
-
162
- def suffix_expression(record, suffixs)
163
- sub = nil
164
-
165
- suffixs.each do |word|
166
- e = record.suffix =~ word
167
- if sub.nil?
168
- sub = e
169
- else
170
- sub |= e
171
- end
172
- end
173
-
174
- sub
175
- end
176
- private :suffix_expression
177
-
178
- end
179
- end
@@ -1,35 +0,0 @@
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
-
@@ -1,52 +0,0 @@
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
-
@@ -1,39 +0,0 @@
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
- @env = env
19
- @request = Rack::Request.new(env)
20
- @query = Query.new(@request)
21
-
22
- @response = Rack::Response.new
23
- @response["Content-Type"] = "text/html; charset=UTF-8"
24
-
25
- render
26
- end
27
-
28
- private
29
-
30
- def render
31
- r = HTMLRendeler.new(@request.script_name + '/..')
32
- @response.write r.header("gren - help", "gren - help")
33
- @response.write r.sample_code
34
- @response.write r.footer
35
- @response.to_a
36
- end
37
- end
38
- end
39
-
@@ -1,39 +0,0 @@
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
- @env = env
19
- @request = Rack::Request.new(env)
20
- @query = Query.new(@request)
21
-
22
- @response = Rack::Response.new
23
- @response["Content-Type"] = "text/html; charset=UTF-8"
24
-
25
- render
26
- end
27
-
28
- private
29
-
30
- def render
31
- r = HTMLRendeler.new(@request.script_name)
32
- @response.write r.header_home("gren", "gren", Version)
33
- @response.write r.search_box
34
- @response.write r.footer_home("??", Database.instance.fileNum)
35
- @response.to_a
36
- end
37
- end
38
- end
39
-
@@ -1,243 +0,0 @@
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 initialize(script_name)
17
- @script_name = Pathname(script_name)
18
- end
19
-
20
- def header(title, header1)
21
- <<EOS
22
- <?xml version="1.0" encoding="utf-8"?>
23
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
24
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
25
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
26
- <head>
27
- <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
28
- <!-- <meta name="robot" content="noindex,nofollow" /> -->
29
- <title>#{title}</title>
30
- <link rel="stylesheet" href="#{fullpath('css/gren.css')}" type="text/css" media="all" />
31
- </head>
32
- <body>
33
- <div class="header">
34
- <h1>
35
- <a href="#{fullpath('')}"><img src="#{fullpath('images/gren-icon-mini.png')}" alt="gren-icon" border="0"/></a>
36
- #{header1}
37
- </h1>
38
- </div>
39
-
40
- <div class="content">
41
- EOS
42
- end
43
-
44
- def footer
45
- <<EOS
46
- </div>
47
-
48
- <div class="footer">
49
- </div>
50
- </body>
51
- </html>
52
- EOS
53
- end
54
-
55
- def header_home(title, header1, version)
56
- <<EOS
57
- <?xml version="1.0" encoding="utf-8"?>
58
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
59
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
60
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
61
- <head>
62
- <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
63
- <!-- <meta name="robot" content="noindex,nofollow" /> -->
64
- <title>#{title}</title>
65
- <link rel="stylesheet" href="#{fullpath('css/gren.css')}" type="text/css" media="all" />
66
- </head>
67
- <body>
68
- <div align="center">
69
- <div class="header_home">
70
- <h1>
71
- <a href="#{fullpath('')}"><img src="#{fullpath('images/gren-icon.png')}" alt="gren-icon" border="0" height="100px"/></a>
72
- #{header1} <font class="version">#{version}</font>
73
- </h1>
74
- </div>
75
-
76
- <div class="content">
77
- EOS
78
- end
79
-
80
- def footer_home(package, files)
81
- <<EOS
82
- </div>
83
-
84
- <div class="footer_home">
85
- <!-- <a href="#{fullpath('::search/p:*')}">#{package}</a>のパッケージ , -->
86
- <a href="#{fullpath('::search/f:*')}">#{files}</a>のファイル<br>
87
- <a href="#{fullpath('::help')}">ヘルプ</a> ,
88
- <a href="http://ongaeshi.github.com/gren">grenについて</a>
89
- </div>
90
- </div>
91
- </body>
92
- </html>
93
- EOS
94
- end
95
-
96
- def result_record(record, patterns, nth=1)
97
- if (patterns.size > 0)
98
- <<EOS
99
- <dt class='result-record'><a href='#{fullpath("::view/" + Rack::Utils::escape_html(record.shortpath))}'>#{record.shortpath}</a></dt>
100
- <dd>
101
- <pre class='lines'>
102
- #{result_record_match_line(record, patterns, nth)}
103
- </pre>
104
- </dd>
105
- EOS
106
- else
107
- <<EOS
108
- <dt class='result-record'><a href='#{fullpath("::view/" + Rack::Utils::escape_html(record.shortpath))}'>#{record.shortpath}</a></dt>
109
- EOS
110
- end
111
- end
112
-
113
- def result_record_match_line(record, patterns, nth)
114
- str = ""
115
-
116
- grep = Grep.new(record.content)
117
- lines = grep.match_lines_or(patterns)
118
-
119
- unless (lines.empty?)
120
- index = lines[0].index
121
-
122
- (index - nth..index + nth).each do |i|
123
- if (0 <= i && i < grep.content.size)
124
- match_datas = (i == index) ? lines[0].match_datas : []
125
- str << line(i + 1, grep.content[i], match_datas) + "\n"
126
- end
127
- end
128
- end
129
-
130
- str
131
- end
132
-
133
- def record_content(record)
134
- <<EOS
135
- <pre>
136
- #{record_content_line(record)}
137
- </pre>
138
- EOS
139
- end
140
-
141
- def record_content_line(record)
142
- str = ""
143
-
144
- grep = Grep.new(record.content)
145
- grep.content.each_with_index do |l, index|
146
- str << line(index + 1, l, []) + "\n"
147
- end
148
-
149
- str
150
- end
151
-
152
- def line(lineno, line, match_datas)
153
- sprintf("%5d: %s", lineno, match_strong(Rack::Utils::escape_html(line), match_datas))
154
- end
155
-
156
- def match_strong(line, match_datas)
157
- match_datas.each do |m|
158
- line = line.split(m[0]).join('<strong>' + m[0] + '</strong>') unless (m.nil?)
159
- end
160
-
161
- line
162
- end
163
-
164
- def pagination_link(page, label)
165
- href = "?page=#{page}"
166
- pagination_span("<a href='#{href}'>#{label}</a>")
167
- end
168
-
169
- def pagination_span(content)
170
- "<span class='pagination-link'>#{content}</span>\n"
171
- end
172
-
173
- def empty_summary()
174
- <<EOS
175
- <div class='search-summary'>
176
- <p>gren web検索</p>
177
- </div>
178
- EOS
179
- end
180
-
181
- def search_summary(keyword, total_records, range, elapsed)
182
- <<EOS
183
- <div class='search-summary'>
184
- <span class="keyword">#{keyword}</span>の検索結果:
185
- <span class="total-entries">#{total_records}</span>件中
186
- <span class="display-range">#{range.first} - #{range.last}</span>件(#{elapsed}秒)
187
- </div>
188
- EOS
189
- end
190
-
191
- def view_summary(path, elapsed)
192
- <<EOS
193
- <div class='search-summary'>
194
- <span class="keyword">#{path}</span>(#{elapsed}秒)
195
- </div>
196
- EOS
197
- end
198
-
199
- def search_box(text = "")
200
- <<EOS
201
- <form method="post" action="#{fullpath('::search')}">
202
- <p>
203
- <input name="query" type="text" size="60" value="#{text}" />
204
- <input type="submit" value="検索" />
205
- </p>
206
- </form>
207
- EOS
208
- end
209
-
210
- def sample_code
211
- <<EOS
212
- <div class='sample-code'>
213
- <ol>
214
- <li>キーワードで検索<br>
215
- #{link('def open')}
216
- <li>1フレーズとして検索<br>
217
- #{link('"def open"')}
218
- <li>パッケージ名で絞り込み<br>
219
- #{link('def open p:gren')}
220
- <li>ファイル名や拡張子で絞り込み<br>
221
- #{link('def open f:test s:rb')}
222
- <li>組み合わせ<br>
223
- #{link('p:gren p:tidtools s:rb f:test assert f:cli')}
224
- </ol>
225
- </div>
226
- EOS
227
- end
228
-
229
- def link(keyword)
230
- "<a href='#{fullpath('::search' + '/' + Rack::Utils::escape_html(keyword))}'>#{keyword}</a>"
231
- end
232
-
233
- def fullpath(path)
234
- unless (path == '')
235
- (@script_name + path).to_s
236
- else
237
- @script_name.to_s
238
- end
239
- end
240
- end
241
- end
242
-
243
-