bitclust-core 0.5.4 → 0.5.5

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,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