bitclust-core 0.5.4 → 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,49 @@
1
+ require 'pathname'
2
+ require 'erb'
3
+ require 'find'
4
+ require 'pp'
5
+ require 'optparse'
6
+ require 'yaml'
7
+
8
+ require 'bitclust'
9
+ require 'bitclust/subcommand'
10
+
11
+ module BitClust::Subcommands
12
+ class InitCommand < BitClust::Subcommand
13
+ def initialize
14
+ @parser = OptionParser.new {|opt|
15
+ opt.banner = "Usage: #{File.basename($0, '.*')} init [KEY=VALUE ...]"
16
+ opt.on('--help', 'Prints this message and quit.') {
17
+ puts opt.help
18
+ exit 0
19
+ }
20
+ }
21
+ end
22
+
23
+ STANDARD_PROPERTIES = %w( encoding version )
24
+
25
+ def exec(db, argv)
26
+ db.init
27
+ db.transaction {
28
+ argv.each do |kv|
29
+ k, v = kv.split('=', 2)
30
+ db.propset k, v
31
+ end
32
+ }
33
+ fail = false
34
+ STANDARD_PROPERTIES.each do |key|
35
+ unless db.propget(key)
36
+ $stderr.puts "#{File.basename($0, '.*')}: warning: standard property `#{key}' not given"
37
+ fail = true
38
+ end
39
+ end
40
+ if fail
41
+ $stderr.puts "---- Current Properties ----"
42
+ db.properties.each do |key, value|
43
+ $stderr.puts "#{key}=#{value}"
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
@@ -0,0 +1,68 @@
1
+ require 'pathname'
2
+ require 'erb'
3
+ require 'find'
4
+ require 'pp'
5
+ require 'optparse'
6
+ require 'yaml'
7
+
8
+ require 'bitclust'
9
+ require 'bitclust/subcommand'
10
+
11
+ module BitClust::Subcommands
12
+ class ListCommand < BitClust::Subcommand
13
+ def initialize
14
+ @mode = nil
15
+ @parser = OptionParser.new {|opt|
16
+ opt.banner = "Usage: #{File.basename($0, '.*')} list (--library|--class|--method|--function)"
17
+ opt.on('--library', 'List libraries.') {
18
+ @mode = :library
19
+ }
20
+ opt.on('--class', 'List classes.') {
21
+ @mode = :class
22
+ }
23
+ opt.on('--method', 'List methods.') {
24
+ @mode = :method
25
+ }
26
+ opt.on('--function', 'List functions.') {
27
+ @mode = :function
28
+ }
29
+ opt.on('--help', 'Prints this message and quit.') {
30
+ puts opt.help
31
+ exit 0
32
+ }
33
+ }
34
+ end
35
+
36
+ def parse(argv)
37
+ super
38
+ unless @mode
39
+ error 'one of (--library|--class|--method|--function) is required'
40
+ end
41
+ end
42
+
43
+ def exec(db, argv)
44
+ case @mode
45
+ when :library
46
+ db.libraries.map {|lib| lib.name }.sort.each do |name|
47
+ puts name
48
+ end
49
+ when :class
50
+ db.classes.map {|c| c.name }.sort.each do |name|
51
+ puts name
52
+ end
53
+ when :method
54
+ db.classes.sort_by {|c| c.name }.each do |c|
55
+ c.entries.sort_by {|m| m.id }.each do |m|
56
+ puts m.label
57
+ end
58
+ end
59
+ when :function
60
+ db.functions.sort_by {|f| f.name }.each do |f|
61
+ puts f.name
62
+ end
63
+ else
64
+ raise "must not happen: @mode=#{@mode.inspect}"
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,176 @@
1
+ require 'pathname'
2
+ require 'erb'
3
+ require 'find'
4
+ require 'pp'
5
+ require 'optparse'
6
+ require 'yaml'
7
+
8
+ require 'bitclust'
9
+ require 'bitclust/subcommand'
10
+
11
+ module BitClust::Subcommands
12
+ class LookupCommand < BitClust::Subcommand
13
+ def initialize
14
+ @format = :text
15
+ @type = nil
16
+ @key = nil
17
+ @parser = OptionParser.new {|opt|
18
+ opt.banner = "Usage: #{File.basename($0, '.*')} lookup (--library|--class|--method|--function) [--html] <key>"
19
+ opt.on('--library=NAME', 'Lookup library.') {|name|
20
+ @type = :library
21
+ @key = name
22
+ }
23
+ opt.on('--class=NAME', 'Lookup class.') {|name|
24
+ @type = :class
25
+ @key = name
26
+ }
27
+ opt.on('--method=NAME', 'Lookup method.') {|name|
28
+ @type = :method
29
+ @key = name
30
+ }
31
+ opt.on('--function=NAME', 'Lookup function.') {|name|
32
+ @type = :function
33
+ @key = name
34
+ }
35
+ opt.on('--html', 'Show result in HTML.') {
36
+ @format = :html
37
+ }
38
+ opt.on('--help', 'Prints this message and quit.') {
39
+ puts opt.help
40
+ exit 0
41
+ }
42
+ }
43
+ end
44
+
45
+ def parse(argv)
46
+ super
47
+ unless @type
48
+ error "one of --library/--class/--method/--function is required"
49
+ end
50
+ unless argv.empty?
51
+ error "too many arguments"
52
+ end
53
+ end
54
+
55
+ def exec(db, argv)
56
+ entry = fetch_entry(db, @type, @key)
57
+ puts fill_template(get_template(@type, @format), entry)
58
+ end
59
+
60
+ def fetch_entry(db, type, key)
61
+ case type
62
+ when :library
63
+ db.fetch_library(key)
64
+ when :class
65
+ db.fetch_class(key)
66
+ when :method
67
+ db.fetch_method(BitClust::MethodSpec.parse(key))
68
+ when :function
69
+ db.fetch_function(key)
70
+ else
71
+ raise "must not happen: #{type.inspect}"
72
+ end
73
+ end
74
+
75
+ def fill_template(template, entry)
76
+ ERB.new(template).result(binding())
77
+ end
78
+
79
+ def get_template(type, format)
80
+ template = TEMPLATE[type][format]
81
+ BitClust::TextUtils.unindent_block(template.lines).join('')
82
+ end
83
+
84
+ TEMPLATE = {
85
+ :library => {
86
+ :text => <<-End,
87
+ type: library
88
+ name: <%= entry.name %>
89
+ classes: <%= entry.classes.map {|c| c.name }.sort.join(', ') %>
90
+ methods: <%= entry.methods.map {|m| m.name }.sort.join(', ') %>
91
+
92
+ <%= entry.source %>
93
+ End
94
+ :html => <<-End
95
+ <dl>
96
+ <dt>type</dt><dd>library</dd>
97
+ <dt>name</dt><dd><%= entry.name %></dd>
98
+ <dt>classes</dt><dd><%= entry.classes.map {|c| c.name }.sort.join(', ') %></dd>
99
+ <dt>methods</dt><dd><%= entry.methods.map {|m| m.name }.sort.join(', ') %></dd>
100
+ </dl>
101
+ <%= compile_rd(entry.source) %>
102
+ End
103
+ },
104
+ :class => {
105
+ :text => <<-End,
106
+ type: class
107
+ name: <%= entry.name %>
108
+ library: <%= entry.library.name %>
109
+ singleton_methods: <%= entry.singleton_methods.map {|m| m.name }.sort.join(', ') %>
110
+ instance_methods: <%= entry.instance_methods.map {|m| m.name }.sort.join(', ') %>
111
+ constants: <%= entry.constants.map {|m| m.name }.sort.join(', ') %>
112
+ special_variables: <%= entry.special_variables.map {|m| '$' + m.name }.sort.join(', ') %>
113
+
114
+ <%= entry.source %>
115
+ End
116
+ :html => <<-End
117
+ <dl>
118
+ <dt>type</dt><dd>class</dd>
119
+ <dt>name</dt><dd><%= entry.name %></dd>
120
+ <dt>library</dt><dd><%= entry.library.name %></dd>
121
+ <dt>singleton_methods</dt><dd><%= entry.singleton_methods.map {|m| m.name }.sort.join(', ') %></dd>
122
+ <dt>instance_methods</dt><dd><%= entry.instance_methods.map {|m| m.name }.sort.join(', ') %></dd>
123
+ </dl>
124
+ <%= compile_rd(entry.source) %>
125
+ End
126
+ },
127
+ :method => {
128
+ :text => <<-End,
129
+ type: <%= entry.type %>
130
+ name: <%= entry.name %>
131
+ names: <%= entry.names.sort.join(', ') %>
132
+ visibility: <%= entry.visibility %>
133
+ kind: <%= entry.kind %>
134
+ library: <%= entry.library.name %>
135
+
136
+ <%= entry.source %>
137
+ End
138
+ :html => <<-End
139
+ <dl>
140
+ <dt>type</dt><dd><%= entry.type %></dd>
141
+ <dt>name</dt><dd><%= entry.name %></dd>
142
+ <dt>names</dt><dd><%= entry.names.sort.join(', ') %></dd>
143
+ <dt>visibility</dt><dd><%= entry.visibility %></dd>
144
+ <dt>kind</dt><dd><%= entry.kind %></dd>
145
+ <dt>library</dt><dd><%= entry.library.name %></dd>
146
+ </dl>
147
+ <%= compile_rd(entry.source) %>
148
+ End
149
+ },
150
+ :function => {
151
+ :text => <<-End,
152
+ kind: <%= entry.kind %>
153
+ header: <%= entry.header %>
154
+ filename: <%= entry.filename %>
155
+
156
+ <%= entry.source %>
157
+ End
158
+ :html => <<-End
159
+ <dl>
160
+ <dt>kind</dt><dd><%= entry.kind %></dd>
161
+ <dt>header</dt><dd><%= entry.header %></dd>
162
+ <dt>filename</dt><dd><%= entry.filename %></dd>
163
+ </dl>
164
+ <%= compile_rd(entry.source) %>
165
+ End
166
+ }
167
+ }
168
+
169
+ def compile_rd(src)
170
+ umap = BitClust::URLMapper.new(:base_url => 'http://example.com',
171
+ :cgi_url => 'http://example.com/view')
172
+ compiler = BitClust::RDCompiler.new(umap, 2)
173
+ compiler.compile(src)
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,74 @@
1
+ require 'pathname'
2
+ require 'erb'
3
+ require 'find'
4
+ require 'pp'
5
+ require 'optparse'
6
+ require 'yaml'
7
+
8
+ require 'bitclust'
9
+ require 'bitclust/subcommand'
10
+
11
+ module BitClust::Subcommands
12
+ class PropertyCommand < BitClust::Subcommand
13
+ def initialize
14
+ @mode = nil
15
+ @parser = OptionParser.new {|opt|
16
+ opt.banner = "Usage: #{File.basename($0, '.*')} property [options]"
17
+ opt.on('--list', 'List all properties.') {
18
+ @mode = :list
19
+ }
20
+ opt.on('--get', 'Get property value.') {
21
+ @mode = :get
22
+ }
23
+ opt.on('--set', 'Set property value.') {
24
+ @mode = :set
25
+ }
26
+ opt.on('--help', 'Prints this message and quit.') {
27
+ puts opt.help
28
+ exit 0
29
+ }
30
+ }
31
+ end
32
+
33
+ def parse(argv)
34
+ super
35
+ unless @mode
36
+ error "one of (--list|--get|--set) is required"
37
+ end
38
+ case @mode
39
+ when :list
40
+ unless argv.empty?
41
+ error "--list requires no argument"
42
+ end
43
+ when :get
44
+ ;
45
+ when :set
46
+ unless argv.size == 2
47
+ error "--set requires just 2 arguments"
48
+ end
49
+ else
50
+ raise "must not happen: #{@mode}"
51
+ end
52
+ end
53
+
54
+ def exec(db, argv)
55
+ case @mode
56
+ when :list
57
+ db.properties.each do |key, val|
58
+ puts "#{key}=#{val}"
59
+ end
60
+ when :get
61
+ argv.each do |key|
62
+ puts db.propget(key)
63
+ end
64
+ when :set
65
+ key, val = *argv
66
+ db.transaction {
67
+ db.propset key, val
68
+ }
69
+ else
70
+ raise "must not happen: #{@mode}"
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,34 @@
1
+ require 'pathname'
2
+ require 'erb'
3
+ require 'find'
4
+ require 'pp'
5
+ require 'optparse'
6
+ require 'yaml'
7
+
8
+ require 'bitclust'
9
+ require 'bitclust/subcommand'
10
+
11
+ module BitClust::Subcommands
12
+ class QueryCommand < BitClust::Subcommand
13
+
14
+ def initialize
15
+ @parser = OptionParser.new {|opt|
16
+ opt.banner = "Usage: #{File.basename($0, '.*')} query <ruby-script>"
17
+ opt.on('--help', 'Prints this message and quit.') {
18
+ puts opt.help
19
+ exit 0
20
+ }
21
+ }
22
+ end
23
+
24
+ def parse(argv)
25
+ end
26
+
27
+ def exec(db, argv)
28
+ argv.each do |query|
29
+ #pp eval(query) # FIXME: causes ArgumentError
30
+ p eval(query)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,218 @@
1
+ require 'pathname'
2
+ require 'erb'
3
+ require 'find'
4
+ require 'pp'
5
+ require 'optparse'
6
+ require 'yaml'
7
+ require 'webrick'
8
+ require 'uri'
9
+
10
+ require 'bitclust'
11
+ require 'bitclust/subcommand'
12
+
13
+ module BitClust::Subcommands
14
+ class ServerCommand < BitClust::Subcommand
15
+ def initialize
16
+ require 'webrick'
17
+ require 'uri'
18
+
19
+ @params = {
20
+ :BindAddress => "0.0.0.0",
21
+ :Port => 10080
22
+ }
23
+ @baseurl = nil
24
+ @dbpath = nil
25
+ @srcdir = @datadir = @themedir = @theme = @templatedir = nil
26
+ @encoding = 'utf-8' # encoding of view
27
+ if Object.const_defined?(:Encoding)
28
+ Encoding.default_external = @encoding
29
+ end
30
+
31
+ @debugp = false
32
+ @autop = false
33
+ @browser = nil
34
+ @pid_file = nil
35
+ @capi = false
36
+
37
+ @parser = OptionParser.new
38
+ @parser.banner = "#{$0} [--bind-address=ADDR] [--port=NUM] --baseurl=URL --database=PATH [--srcdir=PATH] [--datadir=PATH] [--themedir=PATH] [--debug] [--auto] [--browser=BROWSER] [--pid-file=PATH] [--capi]"
39
+ @parser.on('--bind-address=ADDR', 'Bind address') {|addr|
40
+ @params[:BindAddress] = addr
41
+ }
42
+ @parser.on('--port=NUM', 'Listening port number') {|num|
43
+ @params[:Port] = num.to_i
44
+ }
45
+ @parser.on('--baseurl=URL', 'The base URL to host.') {|url|
46
+ @baseurl = url
47
+ }
48
+ @parser.on('--database=PATH', 'MethodDatabase root directory.') {|path|
49
+ @dbpath = path
50
+ }
51
+ @parser.on('--srcdir=PATH', 'BitClust source directory.') {|path|
52
+ set_srcdir(path)
53
+ }
54
+ @parser.on('--datadir=PATH', 'BitClust data directory.') {|path|
55
+ @datadir = path
56
+ }
57
+ @parser.on('--templatedir=PATH', 'Template directory.') {|path|
58
+ @templatedir = path
59
+ }
60
+ @parser.on('--themedir=PATH', 'BitClust theme directory.') {|path|
61
+ @themedir = path
62
+ }
63
+ @parser.on('--theme=THEME', 'BitClust theme.') {|th|
64
+ @theme = th
65
+ }
66
+ @parser.on('--[no-]debug', 'Debug mode.') {|flag|
67
+ @debugp = flag
68
+ }
69
+ @parser.on('--[no-]auto', 'Auto mode.') {|flag|
70
+ @autop = flag
71
+ }
72
+ @parser.on('--browser=BROWSER', 'Open with the browser.') {|path|
73
+ @browser = path
74
+ }
75
+ @parser.on('--pid-file=PATH', 'Write pid of the daemon to the specified file.') {|path|
76
+ @pid_file = path
77
+ }
78
+ @parser.on('--help', 'Prints this message and quit.') {
79
+ puts @parser.help
80
+ exit 0
81
+ }
82
+ @parser.on('--capi', 'see also FunctionDatabase.') {|path|
83
+ @capi = true
84
+ }
85
+ end
86
+
87
+ def parse(argv)
88
+ super
89
+ load_config_file
90
+ set_srcdir(srcdir_root) unless @srcdir
91
+
92
+ unless @baseurl
93
+ $stderr.puts "missing base URL. Use --baseurl or check ~/.bitclust/config"
94
+ exit 1
95
+ end
96
+ unless @dbpath || @autop
97
+ $stderr.puts "missing database path. Use --database"
98
+ exit 1
99
+ end
100
+ unless @datadir
101
+ $stderr.puts "missing datadir. Use --datadir"
102
+ exit 1
103
+ end
104
+ unless @themedir
105
+ $stderr.puts "missing themedir. Use --themedir"
106
+ exit 1
107
+ end
108
+ if @pid_file
109
+ if File.exist?(@pid_file)
110
+ $stderr.puts "There is still #{@pid_file}. Is another process running?"
111
+ exit 1
112
+ end
113
+ @pid_file = File.expand_path(@pid_file)
114
+ end
115
+ end
116
+
117
+ def exec(db, argv)
118
+ require 'bitclust/app'
119
+ if @debugp
120
+ @params[:Logger] = WEBrick::Log.new($stderr, WEBrick::Log::DEBUG)
121
+ @params[:AccessLog] = [
122
+ [ $stderr, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
123
+ [ $stderr, WEBrick::AccessLog::REFERER_LOG_FORMAT ],
124
+ [ $stderr, WEBrick::AccessLog::AGENT_LOG_FORMAT ],
125
+ ]
126
+ else
127
+ @params[:Logger] = WEBrick::Log.new($stderr, WEBrick::Log::INFO)
128
+ @params[:AccessLog] = []
129
+ end
130
+ basepath = URI.parse(@baseurl).path
131
+ server = WEBrick::HTTPServer.new(@params)
132
+
133
+ if @autop
134
+ app = BitClust::App.new(
135
+ :dbpath => Dir.glob("#{@database_prefix}-*"),
136
+ :baseurl => @baseurl,
137
+ :datadir => @datadir,
138
+ :templatedir => @templatedir,
139
+ :theme => @theme,
140
+ :encoding => @encoding,
141
+ :capi => @capi
142
+ )
143
+ app.interfaces.each do |version, interface|
144
+ server.mount(File.join(basepath, version), interface)
145
+ end
146
+ server.mount(File.join(basepath, '/'), app)
147
+ else
148
+ viewpath = File.join(basepath, 'view')
149
+ app = BitClust::App.new(
150
+ :viewpath => viewpath,
151
+ :dbpath => @dbpath,
152
+ :baseurl => @baseurl,
153
+ :datadir => @datadir,
154
+ :templatedir => @templatedir,
155
+ :theme => @theme,
156
+ :encoding => @encoding,
157
+ :capi => @capi
158
+ )
159
+ app.interfaces.each do |viewpath, interface|
160
+ server.mount viewpath, interface
161
+ end
162
+ # Redirect from '/' to "#{viewpath}/"
163
+ server.mount('/', app)
164
+ end
165
+
166
+ server.mount File.join(basepath, 'theme/'), WEBrick::HTTPServlet::FileHandler, @themedir
167
+
168
+ if @debugp
169
+ trap(:INT) { server.shutdown }
170
+ else
171
+ WEBrick::Daemon.start do
172
+ trap(:TERM) {
173
+ server.shutdown
174
+ begin
175
+ File.unlink @pid_file if @pid_file
176
+ rescue Errno::ENOENT
177
+ end
178
+ }
179
+ File.open(@pid_file, 'w') {|f| f.write Process.pid } if @pid_file
180
+ end
181
+ end
182
+ exit if $".include?("exerb/mkexy.rb")
183
+ if @autop && !@browser
184
+ case RUBY_PLATFORM
185
+ when /mswin/
186
+ @browser = "start"
187
+ end
188
+ end
189
+ system("#{browser} http://localhost:#{params[:Port]}/") if @browser
190
+ server.start
191
+ end
192
+
193
+ private
194
+
195
+ def srcdir_root
196
+ Pathname.new(__FILE__).realpath.dirname.parent.parent.parent.cleanpath
197
+ end
198
+
199
+ def set_srcdir(dir)
200
+ @srcdir ||= dir
201
+ @datadir ||= "#{@srcdir}/data/bitclust"
202
+ @themedir ||= "#{@srcdir}/theme"
203
+ end
204
+
205
+ def load_config_file
206
+ home_directory = Pathname(ENV['HOME'])
207
+ config_path = home_directory + ".bitclust/config"
208
+ if config_path.exist?
209
+ config = YAML.load_file(config_path)
210
+ @baseurl ||= config[:baseurl]
211
+ @dbpath ||= "#{config[:database_prefix]}-#{config[:default_version]}"
212
+ @port ||= config[:port]
213
+ @pid_file ||= config[:pid_file]
214
+ @database_prefix ||= config[:database_prefix]
215
+ end
216
+ end
217
+ end
218
+ end