codestock 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/.document +5 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +18 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/bin/cdstk +12 -0
- data/bin/cdv +11 -0
- data/bin/cdview +11 -0
- data/bin/cdweb +11 -0
- data/codestock.gemspec +131 -0
- data/lib/codestock.rb +0 -0
- data/lib/common/dbdir.rb +37 -0
- data/lib/common/display_util.rb +62 -0
- data/lib/common/grenfiletest.rb +19 -0
- data/lib/common/grensnip.rb +37 -0
- data/lib/common/platform.rb +17 -0
- data/lib/common/string_snip.rb +61 -0
- data/lib/common/util.rb +98 -0
- data/lib/findgrep/findgrep.rb +408 -0
- data/lib/findgrep/result.rb +43 -0
- data/lib/gren/cli.rb +65 -0
- data/lib/gren.rb +6 -0
- data/lib/grendb/cli.rb +43 -0
- data/lib/grenweb/cli.rb +54 -0
- data/lib/grenweb/database.rb +182 -0
- data/lib/grenweb/grenweb.ru +35 -0
- data/lib/grenweb/grep.rb +52 -0
- data/lib/grenweb/help.rb +40 -0
- data/lib/grenweb/home.rb +40 -0
- data/lib/grenweb/html_renderer.rb +244 -0
- data/lib/grenweb/public/css/gren.css +63 -0
- data/lib/grenweb/public/images/gren-icon-mini.png +0 -0
- data/lib/grenweb/public/images/gren-icon.png +0 -0
- data/lib/grenweb/query.rb +82 -0
- data/lib/grenweb/searcher.rb +130 -0
- data/lib/grenweb/viewer.rb +52 -0
- data/lib/mkgrendb/cli.rb +89 -0
- data/lib/mkgrendb/cli_old.rb +49 -0
- data/lib/mkgrendb/grendbyaml.rb +76 -0
- data/lib/mkgrendb/mkgrendb.rb +296 -0
- data/test/file_test_utils.rb +59 -0
- data/test/runner.rb +11 -0
- data/test/test_dbdir.rb +59 -0
- data/test/test_gren.rb +10 -0
- data/test/test_gren_util.rb +34 -0
- data/test/test_grendbyaml.rb +109 -0
- data/test/test_grenweb_cli.rb +10 -0
- data/test/test_grenweb_database.rb +37 -0
- data/test/test_grenweb_html_renderer.rb +41 -0
- data/test/test_grenweb_query.rb +54 -0
- data/test/test_grenweb_searcher.rb +35 -0
- data/test/test_helper.rb +2 -0
- data/test/test_mkgrendb.rb +163 -0
- data/test/test_string_snip.rb +31 -0
- metadata +229 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# @file
|
4
|
+
# @brief クエリーの解析
|
5
|
+
# @author ongaeshi
|
6
|
+
# @date 2010/10/21
|
7
|
+
|
8
|
+
require 'rubygems'
|
9
|
+
require 'rack'
|
10
|
+
|
11
|
+
module Grenweb
|
12
|
+
class Query
|
13
|
+
include Rack::Utils
|
14
|
+
attr_reader :query_string
|
15
|
+
|
16
|
+
OPTIONS = [
|
17
|
+
['package', 'p'],
|
18
|
+
['filepath', 'fpath', 'f'],
|
19
|
+
['suffix', 's'],
|
20
|
+
]
|
21
|
+
|
22
|
+
def initialize(request)
|
23
|
+
@query_string = unescape(request.path_info.gsub(/\A\/|\/\z/, ''))
|
24
|
+
init_hash
|
25
|
+
parse
|
26
|
+
end
|
27
|
+
|
28
|
+
def escape_html
|
29
|
+
Rack::Utils::escape_html(@query_string)
|
30
|
+
end
|
31
|
+
|
32
|
+
def empty?
|
33
|
+
keywords.size == 0 && packages.size == 0 && fpaths.size == 0 && suffixs.size == 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def keywords
|
37
|
+
@hash['keywords']
|
38
|
+
end
|
39
|
+
|
40
|
+
def packages
|
41
|
+
calc_param(0)
|
42
|
+
end
|
43
|
+
|
44
|
+
def fpaths
|
45
|
+
calc_param(1)
|
46
|
+
end
|
47
|
+
|
48
|
+
def suffixs
|
49
|
+
calc_param(2)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def calc_param(index)
|
55
|
+
OPTIONS[index].inject([]){|result, item| result.concat @hash[item] }
|
56
|
+
end
|
57
|
+
|
58
|
+
def init_hash
|
59
|
+
@hash = {}
|
60
|
+
@hash['keywords'] = []
|
61
|
+
|
62
|
+
OPTIONS.flatten.each do |key|
|
63
|
+
@hash[key] = []
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def parse
|
68
|
+
kp = OPTIONS.flatten.join('|')
|
69
|
+
parts = @query_string.scan(/(?:(#{kp}):)?(?:"(.+)"|(\S+))/)
|
70
|
+
|
71
|
+
parts.each do |key, quoted_value, value|
|
72
|
+
text = quoted_value || value
|
73
|
+
unless (key)
|
74
|
+
@hash['keywords'] << text
|
75
|
+
else
|
76
|
+
@hash[key] << text
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# @file
|
4
|
+
# @brief 検索処理本体
|
5
|
+
# @author ongaeshi
|
6
|
+
# @date 2010/10/13
|
7
|
+
|
8
|
+
require 'rubygems'
|
9
|
+
require 'rack'
|
10
|
+
require File.join(File.dirname(__FILE__), 'database')
|
11
|
+
require File.join(File.dirname(__FILE__), 'html_renderer')
|
12
|
+
require File.join(File.dirname(__FILE__), 'query')
|
13
|
+
|
14
|
+
module Grenweb
|
15
|
+
class Searcher
|
16
|
+
include Rack::Utils
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(env)
|
22
|
+
@request = Rack::Request.new(env)
|
23
|
+
@query = Query.new(@request)
|
24
|
+
|
25
|
+
@response = Rack::Response.new
|
26
|
+
@response["Content-Type"] = "text/html; charset=UTF-8"
|
27
|
+
|
28
|
+
@nth = 3 # マッチした行の前後何行を表示するか
|
29
|
+
|
30
|
+
@rendeler = HTMLRendeler.new(@request.script_name + '/..')
|
31
|
+
|
32
|
+
if @request.post? or @request['query']
|
33
|
+
post_request
|
34
|
+
else
|
35
|
+
search
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def post_request
|
42
|
+
query = @request['query'] || ''
|
43
|
+
if query.empty?
|
44
|
+
@request.path_info = "/"
|
45
|
+
else
|
46
|
+
@request.path_info = "/#{escape(query)}/"
|
47
|
+
end
|
48
|
+
@response.redirect(@request.url.split(/\?/, 2)[0])
|
49
|
+
@response.to_a
|
50
|
+
end
|
51
|
+
|
52
|
+
def search
|
53
|
+
render_header
|
54
|
+
render_search_box
|
55
|
+
render_search_result
|
56
|
+
render_footer
|
57
|
+
@response.to_a
|
58
|
+
end
|
59
|
+
|
60
|
+
def render_header
|
61
|
+
@response.write @rendeler.header("gren : #{@query.escape_html}", "gren")
|
62
|
+
end
|
63
|
+
|
64
|
+
def render_search_box
|
65
|
+
@response.write @rendeler.search_box(@query.escape_html)
|
66
|
+
end
|
67
|
+
|
68
|
+
def render_search_result
|
69
|
+
if @query.empty?
|
70
|
+
@response.write @rendeler.empty_summary
|
71
|
+
else
|
72
|
+
records, total_records, elapsed = Database.instance.search(@query.keywords, @query.packages, @query.fpaths, @query.suffixs, calcPage, calcLimit)
|
73
|
+
render_search_summary(records, total_records, elapsed)
|
74
|
+
records.each { |record| @response.write(@rendeler.result_record(record, @query.keywords, @nth)) }
|
75
|
+
render_pagination(calcPage, total_records)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def render_search_summary(records, total_records, elapsed)
|
80
|
+
pageStart = calcPage * calcLimit
|
81
|
+
@response.write @rendeler.search_summary(@query.query_string,
|
82
|
+
total_records,
|
83
|
+
(total_records.zero? ? 0 : pageStart + 1)..(pageStart + records.size),
|
84
|
+
elapsed)
|
85
|
+
end
|
86
|
+
|
87
|
+
def render_pagination(page, total_records)
|
88
|
+
return if @query.empty?
|
89
|
+
return if total_records < calcLimit
|
90
|
+
|
91
|
+
last_page = (total_records / calcLimit.to_f).ceil
|
92
|
+
@response.write("<div class='pagination'>\n")
|
93
|
+
if page > 0
|
94
|
+
@response.write(@rendeler.pagination_link(page - 1, "<<"))
|
95
|
+
end
|
96
|
+
last_page.times do |i|
|
97
|
+
if i == page
|
98
|
+
@response.write(@rendeler.pagination_span(i))
|
99
|
+
else
|
100
|
+
@response.write(@rendeler.pagination_link(i, i))
|
101
|
+
end
|
102
|
+
end
|
103
|
+
if page < (last_page - 1)
|
104
|
+
@response.write(@rendeler.pagination_link(page + 1, ">>"))
|
105
|
+
end
|
106
|
+
@response.write("</div>\n")
|
107
|
+
end
|
108
|
+
|
109
|
+
def render_footer
|
110
|
+
@response.write @rendeler.footer
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
# 1ページに表示する最大レコードを計算
|
116
|
+
def calcLimit
|
117
|
+
if @query.keywords.size == 0
|
118
|
+
100
|
119
|
+
else
|
120
|
+
20
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# 現在ページを計算
|
125
|
+
def calcPage
|
126
|
+
(@request['page'] || 0).to_i
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# @file
|
4
|
+
# @brief ソースコードを表示する
|
5
|
+
# @author ongaeshi
|
6
|
+
# @date 2010/10/13
|
7
|
+
|
8
|
+
require 'rubygems'
|
9
|
+
require 'rack'
|
10
|
+
require File.join(File.dirname(__FILE__), 'database')
|
11
|
+
require File.join(File.dirname(__FILE__), 'html_renderer')
|
12
|
+
|
13
|
+
module Grenweb
|
14
|
+
class Viewer
|
15
|
+
include Rack::Utils
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
@request = Rack::Request.new(env)
|
22
|
+
@response = Rack::Response.new
|
23
|
+
@response["Content-Type"] = "text/html; charset=UTF-8"
|
24
|
+
|
25
|
+
record, elapsed = Database.instance.record(req2query)
|
26
|
+
|
27
|
+
@rendeler = HTMLRendeler.new(@request.script_name + '/..')
|
28
|
+
|
29
|
+
if (record)
|
30
|
+
@response.write @rendeler.header("gren : #{record.shortpath}", "gren")
|
31
|
+
@response.write @rendeler.search_box("")
|
32
|
+
@response.write @rendeler.view_summary(record.shortpath, elapsed)
|
33
|
+
@response.write @rendeler.record_content(record)
|
34
|
+
else
|
35
|
+
@response.write @rendeler.header("gren : not found.", "gren")
|
36
|
+
@response.write @rendeler.search_box("")
|
37
|
+
@response.write @rendeler.empty_summary
|
38
|
+
end
|
39
|
+
@response.write @rendeler.footer
|
40
|
+
|
41
|
+
@response.to_a
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def req2query
|
47
|
+
p @request.path_info
|
48
|
+
unescape(@request.path_info.gsub(/\A\/|\/z/, ''))
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
data/lib/mkgrendb/cli.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'optparse'
|
3
|
+
require File.join(File.dirname(__FILE__), 'mkgrendb')
|
4
|
+
require File.join(File.dirname(__FILE__), '../common/dbdir.rb')
|
5
|
+
include CodeStock
|
6
|
+
|
7
|
+
module Mkgrendb
|
8
|
+
class CLI
|
9
|
+
def self.execute(stdout, arguments=[])
|
10
|
+
opt = OptionParser.new <<EOF
|
11
|
+
#{File.basename($0)} COMMAND [ARGS]
|
12
|
+
|
13
|
+
The most commonly used mkgrendb are:
|
14
|
+
init Init db.
|
15
|
+
update Update db.
|
16
|
+
add Add contents. (ex. ~/Documents/gren, git://github.com/ongaeshi/gren.git)
|
17
|
+
remove Remove contents.
|
18
|
+
list List all contents.
|
19
|
+
rebuild Rebuild db.
|
20
|
+
dump Dump database contents.
|
21
|
+
EOF
|
22
|
+
|
23
|
+
subopt = Hash.new
|
24
|
+
|
25
|
+
init_default = false
|
26
|
+
subopt['init'] = OptionParser.new("#{File.basename($0)} init")
|
27
|
+
subopt['init'].on('--default', 'Init db default path. (Maybe ~/.codestock)') { init_default = true }
|
28
|
+
|
29
|
+
subopt['update'] = OptionParser.new("#{File.basename($0)} update")
|
30
|
+
subopt['add'] = OptionParser.new("#{File.basename($0)} add content1 [content2 ...]")
|
31
|
+
subopt['remove'] = OptionParser.new("#{File.basename($0)} remove content1 [content2 ...]")
|
32
|
+
subopt['list'] = OptionParser.new("#{File.basename($0)} list")
|
33
|
+
subopt['rebuild'] = OptionParser.new("#{File.basename($0)} rebuild")
|
34
|
+
subopt['dump'] = OptionParser.new("#{File.basename($0)} dump")
|
35
|
+
|
36
|
+
opt.order!(arguments)
|
37
|
+
subcommand = arguments.shift
|
38
|
+
|
39
|
+
if (subopt[subcommand])
|
40
|
+
subopt[subcommand].parse!(arguments) unless arguments.empty?
|
41
|
+
|
42
|
+
db_dir = select_dbdir(subcommand, init_default)
|
43
|
+
obj = Mkgrendb.new(stdout, db_dir)
|
44
|
+
|
45
|
+
case subcommand
|
46
|
+
when 'init'
|
47
|
+
FileUtils.mkdir_p db_dir if (init_default)
|
48
|
+
obj.init
|
49
|
+
when 'update'
|
50
|
+
obj.update
|
51
|
+
when 'add'
|
52
|
+
obj.add *arguments
|
53
|
+
when 'remove'
|
54
|
+
obj.remove *arguments
|
55
|
+
when 'list'
|
56
|
+
obj.list
|
57
|
+
when 'rebuild'
|
58
|
+
obj.rebuild
|
59
|
+
when 'dump'
|
60
|
+
obj.dump
|
61
|
+
end
|
62
|
+
else
|
63
|
+
if subcommand
|
64
|
+
$stderr.puts "mkgrendb: '#{subcommand}' is not a mkgrendb command. See 'mkgrendb --help'"
|
65
|
+
else
|
66
|
+
stdout.puts opt.help
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def self.select_dbdir(subcommand, init_default)
|
74
|
+
if (subcommand == 'init')
|
75
|
+
if (init_default)
|
76
|
+
db_default_dir
|
77
|
+
else
|
78
|
+
'.'
|
79
|
+
end
|
80
|
+
else
|
81
|
+
if (dbdir?('.') || !dbdir?(db_default_dir))
|
82
|
+
'.'
|
83
|
+
else
|
84
|
+
db_default_dir
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'optparse'
|
3
|
+
require File.join(File.dirname(__FILE__), 'mkgrendb')
|
4
|
+
|
5
|
+
module Mkgrendb
|
6
|
+
class CLI
|
7
|
+
def self.execute(stdout, arguments=[])
|
8
|
+
input_yamls = []
|
9
|
+
isDump = false
|
10
|
+
isFull = false
|
11
|
+
isDelete = false
|
12
|
+
isReport = false
|
13
|
+
|
14
|
+
opt = OptionParser.new "#{File.basename($0)} INPUT_YAML1 [INPUT_YAML2 ...]"
|
15
|
+
opt.on('--ddb', "--default-db", "Create or Update default DB. (Plase set ENV['GRENDB_DEFAULT_DB'])") {|v| input_yamls << ENV['GRENDB_DEFAULT_DB']}
|
16
|
+
opt.on('--full', "Full update DB. (Delete and create)") {|v| isFull = true }
|
17
|
+
opt.on('--delete', "Delete DB. (Not delete yaml)") {|v| isDelete = true }
|
18
|
+
opt.on('--dump', "Dump DB.") {|v| isDump = true }
|
19
|
+
opt.on('--report', "Database Report.") {|v| isReport = true }
|
20
|
+
opt.parse!(arguments)
|
21
|
+
|
22
|
+
input_yamls.concat arguments
|
23
|
+
|
24
|
+
if (input_yamls.size >= 1)
|
25
|
+
input_yamls.each do |input_yaml|
|
26
|
+
obj = Mkgrendb.new(input_yaml)
|
27
|
+
|
28
|
+
if (isFull)
|
29
|
+
obj.full
|
30
|
+
stdout.puts
|
31
|
+
elsif (isDelete)
|
32
|
+
obj.delete
|
33
|
+
stdout.puts
|
34
|
+
elsif (isDump)
|
35
|
+
obj.dump
|
36
|
+
elsif (isReport)
|
37
|
+
obj.report
|
38
|
+
else
|
39
|
+
obj.update
|
40
|
+
stdout.puts
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
else
|
45
|
+
stdout.puts opt.help
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# @file
|
4
|
+
# @brief
|
5
|
+
# @author ongaeshi
|
6
|
+
# @date 2011/02/20
|
7
|
+
|
8
|
+
require 'yaml'
|
9
|
+
require 'pathname'
|
10
|
+
|
11
|
+
module Mkgrendb
|
12
|
+
class GrendbYAML
|
13
|
+
class YAMLAlreadyExist < RuntimeError
|
14
|
+
end
|
15
|
+
|
16
|
+
class YAMLNotExist < RuntimeError
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.create(path = ".")
|
20
|
+
yf = yaml_file(path)
|
21
|
+
raise YAMLAlreadyExist.new if FileTest.exist? yf
|
22
|
+
obj = GrendbYAML.new(yf, {'contents' => [], 'version' => 0.1})
|
23
|
+
obj.save
|
24
|
+
return obj
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.load(path = ".")
|
28
|
+
yf = yaml_file(path)
|
29
|
+
raise YAMLNotExist.new unless FileTest.exist? yf
|
30
|
+
open(yf) do |f|
|
31
|
+
return GrendbYAML.new(yf, YAML.load(f.read()))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def add(*dirs)
|
36
|
+
contents.push(*dirs.map{|v|{"directory" => v}})
|
37
|
+
contents.uniq!
|
38
|
+
end
|
39
|
+
|
40
|
+
def remove(*dirs)
|
41
|
+
dirs.each {|f| contents.delete( {"directory" => f} ) }
|
42
|
+
end
|
43
|
+
|
44
|
+
def save
|
45
|
+
open(@yaml_file, "w") { |f| YAML.dump(@data, f) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def contents
|
49
|
+
@data['contents']
|
50
|
+
end
|
51
|
+
|
52
|
+
def directorys
|
53
|
+
contents.map{|v|v["directory"]}
|
54
|
+
end
|
55
|
+
|
56
|
+
def version
|
57
|
+
@data['version']
|
58
|
+
end
|
59
|
+
|
60
|
+
def list
|
61
|
+
directorys
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.yaml_file(path)
|
65
|
+
(Pathname.new(path) + 'grendb.yaml').to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def initialize(yaml_file, data)
|
71
|
+
@yaml_file = yaml_file
|
72
|
+
@data = data
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|