keight 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +263 -0
- data/Rakefile +92 -0
- data/bench/bench.rb +278 -0
- data/bench/benchmarker.rb +502 -0
- data/bin/k8rb +496 -0
- data/keight.gemspec +36 -0
- data/lib/keight/skeleton/.gitignore +10 -0
- data/lib/keight/skeleton/app/action.rb +98 -0
- data/lib/keight/skeleton/app/api/hello.rb +39 -0
- data/lib/keight/skeleton/app/form/.keep +0 -0
- data/lib/keight/skeleton/app/helper/.keep +0 -0
- data/lib/keight/skeleton/app/model/.keep +0 -0
- data/lib/keight/skeleton/app/model.rb +144 -0
- data/lib/keight/skeleton/app/page/welcome.rb +17 -0
- data/lib/keight/skeleton/app/template/_layout.html.eruby +56 -0
- data/lib/keight/skeleton/app/template/welcome.html.eruby +6 -0
- data/lib/keight/skeleton/app/usecase/.keep +0 -0
- data/lib/keight/skeleton/config/app.rb +29 -0
- data/lib/keight/skeleton/config/app_dev.private +11 -0
- data/lib/keight/skeleton/config/app_dev.rb +8 -0
- data/lib/keight/skeleton/config/app_prod.rb +7 -0
- data/lib/keight/skeleton/config/app_stg.rb +5 -0
- data/lib/keight/skeleton/config/app_test.private +11 -0
- data/lib/keight/skeleton/config/app_test.rb +8 -0
- data/lib/keight/skeleton/config/server_puma.rb +22 -0
- data/lib/keight/skeleton/config/server_unicorn.rb +21 -0
- data/lib/keight/skeleton/config/urlpath_mapping.rb +16 -0
- data/lib/keight/skeleton/config.rb +44 -0
- data/lib/keight/skeleton/config.ru +21 -0
- data/lib/keight/skeleton/index.txt +38 -0
- data/lib/keight/skeleton/static/lib/jquery/1.11.3/jquery.min.js +6 -0
- data/lib/keight/skeleton/static/lib/jquery/1.11.3/jquery.min.js.gz +0 -0
- data/lib/keight/skeleton/static/lib/modernizr/2.8.3/modernizr.min.js +4 -0
- data/lib/keight/skeleton/static/lib/modernizr/2.8.3/modernizr.min.js.gz +0 -0
- data/lib/keight/skeleton/tmp/upload/.keep +0 -0
- data/lib/keight.rb +2017 -0
- data/test/data/example1.jpg +0 -0
- data/test/data/example1.png +0 -0
- data/test/data/multipart.form +0 -0
- data/test/data/wabisabi.js +77 -0
- data/test/data/wabisabi.js.gz +0 -0
- data/test/keight_test.rb +3161 -0
- data/test/oktest.rb +1537 -0
- metadata +114 -0
data/bin/k8rb
ADDED
@@ -0,0 +1,496 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
###
|
5
|
+
### $Release: 0.0.1 $
|
6
|
+
### $Copyright: copyright(c) 2014-2015 kuwata-lab.com all rights reserved $
|
7
|
+
### $License: MIT License $
|
8
|
+
###
|
9
|
+
|
10
|
+
|
11
|
+
require 'digest/sha1'
|
12
|
+
|
13
|
+
require 'keight'
|
14
|
+
require 'baby_erubis'
|
15
|
+
|
16
|
+
|
17
|
+
module K8
|
18
|
+
|
19
|
+
|
20
|
+
class Main
|
21
|
+
|
22
|
+
@__current = nil
|
23
|
+
@__actions = []
|
24
|
+
|
25
|
+
@action = proc do |action_name, desc|
|
26
|
+
options = []
|
27
|
+
method_name = nil
|
28
|
+
tuple = [action_name, desc, options, method_name]
|
29
|
+
@__current = tuple
|
30
|
+
@__actions << tuple
|
31
|
+
end
|
32
|
+
|
33
|
+
@option = proc do |optdef_str, desc|
|
34
|
+
tuple = @__current or
|
35
|
+
raise "@option.() is called without @action.()"
|
36
|
+
tuple[2] << [optdef_str, desc]
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.method_added(method_name)
|
40
|
+
tuple = @__current or return
|
41
|
+
tuple[3] = method_name
|
42
|
+
@__current = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.find_action(name)
|
46
|
+
name = name.to_s
|
47
|
+
return @__actions.find {|tuple| tuple[0].to_s == name }
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.each_action(&block)
|
51
|
+
@__actions.each(&block)
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
###
|
56
|
+
|
57
|
+
def initialize(script_name=nil)
|
58
|
+
@script_name = script_name || File.basename($0) # ex: 'k8rb'
|
59
|
+
end
|
60
|
+
|
61
|
+
attr_reader :script_name
|
62
|
+
|
63
|
+
|
64
|
+
### actions
|
65
|
+
|
66
|
+
@action.(:help, "show help")
|
67
|
+
def do_help(action_name=nil)
|
68
|
+
script = self.script_name
|
69
|
+
sb = []
|
70
|
+
if action_name.nil?
|
71
|
+
sb << "Usage:"
|
72
|
+
sb << " #{script} ACTION [..OPTIONS..]"
|
73
|
+
sb << ""
|
74
|
+
sb << "Actions:"
|
75
|
+
self.class.each_action do |action_name, desc, options, _|
|
76
|
+
next unless desc
|
77
|
+
help = desc.lines.first.chomp()
|
78
|
+
sb << " #{script} %-15s # #{help}" % [action_name, help]
|
79
|
+
end
|
80
|
+
sb << ""
|
81
|
+
sb << "(Tips: try '#{script} help ACTION' for details of each action.)"
|
82
|
+
else
|
83
|
+
tuple = self.class.find_action(action_name) or
|
84
|
+
raise K8::OptionError.new("help #{action_name}: no such action.")
|
85
|
+
action_name, desc, options, method_name = tuple
|
86
|
+
pnames = self.method(method_name).parameters.collect {|kind, pname|
|
87
|
+
case kind
|
88
|
+
when :req ; pname
|
89
|
+
when :opt ; "[#{pname}]"
|
90
|
+
when :rest ; "[#{pname}...]"
|
91
|
+
when :key ; nil
|
92
|
+
else
|
93
|
+
raise "** kind=#{kind.inspect}, pname=#{pname.inspect}"
|
94
|
+
end
|
95
|
+
}.compact()
|
96
|
+
pnames.unshift('') unless pnames.empty?
|
97
|
+
argstr = pnames.join(' ')
|
98
|
+
sb << "#{script} #{action_name} - #{desc}"
|
99
|
+
sb << ""
|
100
|
+
sb << "Usage:"
|
101
|
+
if options.empty?
|
102
|
+
sb << " #{script} #{action_name}#{argstr}"
|
103
|
+
else
|
104
|
+
sb << " #{script} #{action_name} [options]#{argstr}"
|
105
|
+
sb << ""
|
106
|
+
sb << "Options:"
|
107
|
+
options.each do |optdef_str, optdesc|
|
108
|
+
optstr = optdef_str.sub(/\A\s*--/, ' --').sub(/\s+\#\w+\s*\z/, '')
|
109
|
+
sb << " %-20s # %s" % [optstr, optdesc] if optdesc
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
sb << ""
|
114
|
+
sb << ""
|
115
|
+
return sb.join("\n")
|
116
|
+
end
|
117
|
+
|
118
|
+
@action.(:init, "create project files")
|
119
|
+
@option.("-s, --skeleton=DIR", "directory of skeleton files")
|
120
|
+
def do_init(project_name, dir: nil)
|
121
|
+
dir ||= K8::FILEPATH.sub(/\.rb\z/, '') + "/skeleton"
|
122
|
+
if dir
|
123
|
+
File.directory?(dir) or
|
124
|
+
raise "#{dir}: directory not exist."
|
125
|
+
o = K8::FileTool.new
|
126
|
+
descs = o.parse_index_file("#{dir}/index.txt")
|
127
|
+
o.mkdir(project_name, "project root directory")
|
128
|
+
files = Dir.glob("#{dir}/**/*")
|
129
|
+
files.concat(["#{dir}/.gitignore"])
|
130
|
+
files.each do |path|
|
131
|
+
base = path[(dir.length+1)..-1]
|
132
|
+
if base == "index.txt"
|
133
|
+
next
|
134
|
+
elsif base =~ /\/\.keep\z/
|
135
|
+
next
|
136
|
+
elsif File.directory?(path)
|
137
|
+
o.mkdir("#{project_name}/#{base}", descs[base+"/"])
|
138
|
+
elsif File.file?(path)
|
139
|
+
content = path =~ /\Astatic\/lib|\.gz\z/ \
|
140
|
+
? File.read(path, encoding: 'ascii-8bit') \
|
141
|
+
: K8::SkeletonTemplate.new.from_file(path, 'ascii-8bit').render()
|
142
|
+
o.mkfile("#{project_name}/#{base}", content, descs[base])
|
143
|
+
else
|
144
|
+
next
|
145
|
+
end
|
146
|
+
end
|
147
|
+
return
|
148
|
+
end
|
149
|
+
0
|
150
|
+
end
|
151
|
+
|
152
|
+
@action.(:mapping, "show action mappings")
|
153
|
+
def do_mapping()
|
154
|
+
ENV['APP_MODE'] ||= 'dev'
|
155
|
+
load_config()
|
156
|
+
require './config/urlpath_mapping'
|
157
|
+
app = K8::RackApplication.new
|
158
|
+
$urlpath_mapping.each do |urlpath, children|
|
159
|
+
app.mount(urlpath, children)
|
160
|
+
end
|
161
|
+
return app.show_mappings()
|
162
|
+
end
|
163
|
+
|
164
|
+
@action.(:configs, "list config keys and values")
|
165
|
+
@option.("--getenv", "show actual ENV value")
|
166
|
+
def do_configs(getenv: false)
|
167
|
+
ENV['APP_MODE'] ||= 'dev'
|
168
|
+
load_config()
|
169
|
+
s = ""
|
170
|
+
::Config.each do |key, val, desc, secret|
|
171
|
+
kv = "%-20s = %s" % [key, __var_dump(val, secret, getenv)]
|
172
|
+
s << ("%-43s # %s\n" % [kv, desc]) if desc
|
173
|
+
end
|
174
|
+
return s
|
175
|
+
end
|
176
|
+
|
177
|
+
@action.(:config, "show config value")
|
178
|
+
@option.("--getenv", "show actual ENV value")
|
179
|
+
def do_config(key, getenv: false)
|
180
|
+
key_name = key
|
181
|
+
ENV['APP_MODE'] ||= 'dev'
|
182
|
+
load_config()
|
183
|
+
::Config.each do |key, val, desc, secret|
|
184
|
+
if key.to_s == key_name
|
185
|
+
return __var_dump(val, secret, getenv)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
$stderr.puts "#{key_name}: no such config key."
|
189
|
+
return 1
|
190
|
+
end
|
191
|
+
|
192
|
+
@action.(:'config:check', "check config values")
|
193
|
+
def do_config_check()
|
194
|
+
ENV['APP_MODE'] ||= 'dev'
|
195
|
+
load_config()
|
196
|
+
not_set = []
|
197
|
+
not_env = []
|
198
|
+
::Config.each do |key, val, desc, secret|
|
199
|
+
if val.is_a?(K8::SecretValue)
|
200
|
+
if ! val.name
|
201
|
+
not_set << [key, val, desc]
|
202
|
+
elsif ! ENV[val.name]
|
203
|
+
not_env << [key, val, desc]
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
if not_set.empty? && not_env.empty?
|
208
|
+
puts "ok."
|
209
|
+
return 0
|
210
|
+
else
|
211
|
+
sb = []
|
212
|
+
sb << "**"
|
213
|
+
sb << "** NG!"
|
214
|
+
unless not_set.empty?
|
215
|
+
sb << "**"
|
216
|
+
sb << "** The following configs should be set, but not."
|
217
|
+
sb << "**"
|
218
|
+
not_set.each do |key, val, desc|
|
219
|
+
sb << "** %-20s = %s" % [key, val.inspect]
|
220
|
+
end
|
221
|
+
end
|
222
|
+
unless not_env.empty?
|
223
|
+
sb << "**"
|
224
|
+
sb << "** The following configs expect environment variable, but not set."
|
225
|
+
sb << "**"
|
226
|
+
not_env.each do |key, val, desc|
|
227
|
+
sb << "** %-20s = %s" % [key, val.inspect]
|
228
|
+
end
|
229
|
+
end
|
230
|
+
sb << "**"
|
231
|
+
puts sb.join("\n")
|
232
|
+
return 1
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def __var_dump(val, secret, getenv)
|
237
|
+
if ! val.is_a?(K8::SecretValue)
|
238
|
+
#secret ? '<secret>' : val.inspect
|
239
|
+
val.inspect
|
240
|
+
elsif val.name
|
241
|
+
getenv ? ENV[val.name].inspect : "ENV['#{val.name}']"
|
242
|
+
else
|
243
|
+
'<SECRET>'
|
244
|
+
end
|
245
|
+
end
|
246
|
+
private :__var_dump
|
247
|
+
|
248
|
+
|
249
|
+
if ENV['DEBUG']
|
250
|
+
@action.(:debug, "debug")
|
251
|
+
@option.("-h, --help" , "show help message")
|
252
|
+
@option.("--version" , "print version")
|
253
|
+
#@option.("-f, --file=FILE" , "filename")
|
254
|
+
@option.("-f FILE #file" , "filename")
|
255
|
+
@option.("-i, --indent[=N]" , "indent depth (default 2)")
|
256
|
+
@option.("-s" , "be silent")
|
257
|
+
@option.("-S #silent" , "be silent")
|
258
|
+
@option.("-d[N] #dbg1" , "debug level #1")
|
259
|
+
@option.(" --dbg2[=N]" , "debug level #2")
|
260
|
+
def do_debug(argmnt=nil, help: nil, version: nil, file: nil, indent: nil, s: nil, silent: false, dbg1: nil, dbg2: nil)
|
261
|
+
sb = []
|
262
|
+
sb << "** argmnt = #{argmnt.inspect}"
|
263
|
+
sb << "** help: #{help.inspect}"
|
264
|
+
sb << "** version: #{version.inspect}"
|
265
|
+
sb << "** file: #{file.inspect}"
|
266
|
+
sb << "** indent: #{indent.inspect}"
|
267
|
+
sb << "** s: #{s.inspect}"
|
268
|
+
sb << "** silent: #{silent.inspect}"
|
269
|
+
sb << "** dbg1: #{dbg1.inspect}"
|
270
|
+
sb << "** dbg2: #{dbg2.inspect}"
|
271
|
+
return sb.join("\n")
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
|
276
|
+
###
|
277
|
+
|
278
|
+
def load_config
|
279
|
+
require './config' rescue K8::ConfigError
|
280
|
+
end
|
281
|
+
|
282
|
+
def run(*cmd_args)
|
283
|
+
action_name = cmd_args.shift() || 'help'
|
284
|
+
tuple = self.class.find_action(action_name) or
|
285
|
+
raise K8::OptionError.new("#{action_name}: unknown action.")
|
286
|
+
action_name, desc, options, method_name = tuple
|
287
|
+
optdefs = options.collect {|arr| K8::OptionDefinition.new(*arr) }
|
288
|
+
optparser = K8::OptionParser.new(optdefs)
|
289
|
+
cmd_opts = optparser.parse(cmd_args)
|
290
|
+
func_args = []
|
291
|
+
func_kwds = {}
|
292
|
+
method_params = self.method(method_name).parameters
|
293
|
+
method_params.each do |param_info|
|
294
|
+
kind, pname = param_info
|
295
|
+
case kind
|
296
|
+
when :req
|
297
|
+
! cmd_args.empty? or
|
298
|
+
raise K8::OptionError.new("#{action_name}: argument '#{pname}' required.")
|
299
|
+
func_args << cmd_args.shift()
|
300
|
+
when :opt
|
301
|
+
func_args << cmd_args.shift() # may be nil
|
302
|
+
when :rest
|
303
|
+
func_args.concat(cmd_args)
|
304
|
+
cmd_args.clear()
|
305
|
+
when :key
|
306
|
+
k = pname.to_s
|
307
|
+
func_kwds[pname] = cmd_opts.delete(k) if cmd_opts.key?(k)
|
308
|
+
if cmd_opts.key?(pname.to_s)
|
309
|
+
func_kwds[pname] = cmd_opts.delete(pname.to_s)
|
310
|
+
end
|
311
|
+
else
|
312
|
+
$stderr.puts "*** internal error: kind=#{kind.inspect}, pname=#{pname.inspect}"
|
313
|
+
end
|
314
|
+
end
|
315
|
+
cmd_args.empty? or
|
316
|
+
raise K8::OptionError.new("#{action_name}: too many argument.")
|
317
|
+
cmd_opts.empty? or
|
318
|
+
raise K8::OptionError.new("#{action_name}: keyword arg not defined (#{cmd_opts.inspect}).")
|
319
|
+
if func_kwds.empty?
|
320
|
+
output = __send__(method_name, *func_args)
|
321
|
+
else
|
322
|
+
output = __send__(method_name, *func_args, func_kwds)
|
323
|
+
end
|
324
|
+
return output
|
325
|
+
end
|
326
|
+
|
327
|
+
def self.main
|
328
|
+
status = 0
|
329
|
+
obj = self.new()
|
330
|
+
begin
|
331
|
+
output = obj.run(*ARGV)
|
332
|
+
case output
|
333
|
+
when nil ;
|
334
|
+
when String ; puts output
|
335
|
+
when Integer ; status = output
|
336
|
+
else ; raise "** output=#{output.inspect}"
|
337
|
+
end
|
338
|
+
rescue K8::OptionError => ex
|
339
|
+
$stderr.puts "ERROR (#{obj.script_name}): #{ex}"
|
340
|
+
output = nil
|
341
|
+
status = 1
|
342
|
+
end
|
343
|
+
exit status
|
344
|
+
end
|
345
|
+
|
346
|
+
end
|
347
|
+
|
348
|
+
|
349
|
+
class OptionDefinition
|
350
|
+
|
351
|
+
def initialize(defstr, desc)
|
352
|
+
@defstr = defstr
|
353
|
+
@desc = desc
|
354
|
+
parse(defstr)
|
355
|
+
end
|
356
|
+
|
357
|
+
attr_reader :defstr, :name, :desc, :short, :long, :argstr, :arg_required
|
358
|
+
|
359
|
+
def parse(defstr)
|
360
|
+
case defstr
|
361
|
+
when /\A\s*-(\w),\s+--(\w[-\w]*)(?:=(\S*)|\[=(\S+)\])?(?:\s+\#(\w+))?\z/
|
362
|
+
short, long, arg1, arg2, optname = $1, $2, $3, $4, $5
|
363
|
+
when /\A\s*--(\w[-\w]*)(?:=(\S*)|\[=(\S+)\])?(?:\s+\#(\w+))?\z/
|
364
|
+
short, long, arg1, arg2, optname = nil, $1, $2, $3, $4
|
365
|
+
when /\A\s*-(\w)(?:\s+(\S+)|\[(\S+)\])?(?:\s+\#(\w+))?\z/
|
366
|
+
short, long, arg1, arg2, optname = $1, nil, $2, $3, $4
|
367
|
+
else
|
368
|
+
raise "#{defstr.inspect}: invalid option definition."
|
369
|
+
end
|
370
|
+
@short = short
|
371
|
+
@long = long
|
372
|
+
@argstr = arg1 || arg2
|
373
|
+
@arg_required = !! arg1 # true when option argument is required
|
374
|
+
@name = optname || long || short
|
375
|
+
end
|
376
|
+
|
377
|
+
end
|
378
|
+
|
379
|
+
|
380
|
+
class OptionParser
|
381
|
+
|
382
|
+
def initialize(optdefs)
|
383
|
+
@optdefs = optdefs
|
384
|
+
end
|
385
|
+
|
386
|
+
def parse(cmd_args)
|
387
|
+
options = {}
|
388
|
+
while cmd_args.length > 0 && cmd_args.first.start_with?('-')
|
389
|
+
optstr = cmd_args.shift()
|
390
|
+
if optstr == '--'
|
391
|
+
break
|
392
|
+
elsif optstr.start_with?('--')
|
393
|
+
optstr =~ /\A--(\w+)(?:=(.*))?\z/ or
|
394
|
+
raise OptionError.new("#{optstr}: invalid option.")
|
395
|
+
long, optarg = $1, $2
|
396
|
+
optdef = @optdefs.find {|x| x.long == long } or
|
397
|
+
raise OptionError.new("#{optstr}: unknown option.")
|
398
|
+
if ! optdef.argstr && optarg
|
399
|
+
raise OptionError.new("#{optstr}: unexpected argument.")
|
400
|
+
elsif optdef.arg_required && ! optarg
|
401
|
+
raise OptionError.new("#{optstr}: argument required.")
|
402
|
+
end
|
403
|
+
options[optdef.name] = optarg || true
|
404
|
+
else
|
405
|
+
i = 0; len = optstr.length
|
406
|
+
while (i += 1) < len
|
407
|
+
ch = optstr[i]
|
408
|
+
optdef = @optdefs.find {|x| x.short == ch } or
|
409
|
+
raise OptionError.new("-#{ch}: unknown option.")
|
410
|
+
if ! optdef.argstr # no arg
|
411
|
+
optarg = true
|
412
|
+
elsif ! optdef.arg_required # optional arg
|
413
|
+
optarg = i + 1 < len ? optstr[(i+1)..-1] : true
|
414
|
+
i = len - 1
|
415
|
+
else # required arg
|
416
|
+
optarg = optstr[(i+1)..-1]
|
417
|
+
if optarg.empty?
|
418
|
+
optarg = cmd_args.shift() or
|
419
|
+
raise OptionError.new("-#{ch}: argument required.")
|
420
|
+
end
|
421
|
+
i = len - 1
|
422
|
+
end
|
423
|
+
options[optdef.name] = optarg
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
return options
|
428
|
+
end
|
429
|
+
|
430
|
+
end
|
431
|
+
|
432
|
+
|
433
|
+
class OptionError < StandardError
|
434
|
+
end
|
435
|
+
|
436
|
+
|
437
|
+
class SkeletonTemplate < BabyErubis::Text
|
438
|
+
|
439
|
+
rexp = BabyErubis::Text::PATTERN
|
440
|
+
PATTERN = Regexp.compile(rexp.to_s.sub(/<%/, '\{%').sub(/%>/, '%\}'))
|
441
|
+
|
442
|
+
def pattern
|
443
|
+
PATTERN
|
444
|
+
end
|
445
|
+
|
446
|
+
end
|
447
|
+
|
448
|
+
|
449
|
+
class FileTool
|
450
|
+
|
451
|
+
def initialize(width: 30)
|
452
|
+
@width = width
|
453
|
+
@depth = 0
|
454
|
+
end
|
455
|
+
|
456
|
+
def parse_index_file(index_file)
|
457
|
+
dict = File.open(index_file) {|f|
|
458
|
+
f.grep(/^[^#]/).each_with_object({}) {|line, d|
|
459
|
+
path, desc = line.chomp.split(/\s+/, 2)
|
460
|
+
d[path] = desc
|
461
|
+
}
|
462
|
+
}
|
463
|
+
return dict
|
464
|
+
end
|
465
|
+
|
466
|
+
def report(s, desc)
|
467
|
+
indent = ' ' * @depth
|
468
|
+
puts "%s%-#{@width - indent.length}s # %s" % [indent, s, desc]
|
469
|
+
end
|
470
|
+
|
471
|
+
def mkrootdir(dirpath)
|
472
|
+
@root = dirpath
|
473
|
+
mkdir(dirpath)
|
474
|
+
end
|
475
|
+
|
476
|
+
def mkdir(dirpath, desc)
|
477
|
+
Dir.mkdir dirpath
|
478
|
+
s = dirpath.gsub(/.*?[\/\\]/, ' ') + "/"
|
479
|
+
report(s, desc)
|
480
|
+
end
|
481
|
+
|
482
|
+
def mkfile(filepath, content, desc)
|
483
|
+
File.open(filepath, 'wb') {|dst| dst.write(content) }
|
484
|
+
s = filepath.gsub(/.*?[\/\\]/, ' ')
|
485
|
+
report(s, desc)
|
486
|
+
end
|
487
|
+
|
488
|
+
end
|
489
|
+
|
490
|
+
|
491
|
+
end
|
492
|
+
|
493
|
+
|
494
|
+
#if __FILE__ == $0
|
495
|
+
K8::Main.main() unless defined? NOEXEC_SCRIPT
|
496
|
+
#end
|
data/keight.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
|
4
|
+
Gem::Specification.new do |o|
|
5
|
+
o.name = "keight"
|
6
|
+
o.version = "$Release: 0.0.1 $".split[1]
|
7
|
+
o.author = "makoto kuwata"
|
8
|
+
o.email = "kwa(at)kuwata-lab.com"
|
9
|
+
o.platform = Gem::Platform::RUBY
|
10
|
+
o.homepage = "https://github.com/kwatch/keight/tree/ruby"
|
11
|
+
o.license = "MIT Lisense"
|
12
|
+
o.summary = "Jet-speed webapp framework for Ruby"
|
13
|
+
o.description = <<'END'
|
14
|
+
Keight.rb is the crazy-fast webapp framework for Ruby.
|
15
|
+
It is about 100 times faster than Rails and 20 times faster than Sinatra.
|
16
|
+
|
17
|
+
See https://github.com/kwatch/keight/tree/ruby for details.
|
18
|
+
END
|
19
|
+
|
20
|
+
o.files = Dir[*%w[
|
21
|
+
README.md MIT-LICENSE keight.gemspec setup.rb Rakefile
|
22
|
+
bin/k8rb
|
23
|
+
lib/keight.rb lib/keight/**/*.{[a-z]*} lib/keight/**/.{[a-z]*}
|
24
|
+
test/*_test.rb test/data/* test/oktest.rb
|
25
|
+
bench/bench.rb bench/benchmarker.rb
|
26
|
+
]]
|
27
|
+
#lib/keight.rb lib/keight/**/*
|
28
|
+
o.executables = ["k8rb"]
|
29
|
+
o.bindir = ["bin"]
|
30
|
+
#o.test_files = o.files.grep(/^test\//)
|
31
|
+
o.test_file = "test/keight_test.rb"
|
32
|
+
|
33
|
+
o.required_ruby_version = '>= 2.0'
|
34
|
+
o.add_runtime_dependency 'baby_erubis', '~> 2.1', '>= 2.1.1'
|
35
|
+
#o.add_development_dependency "oktest", "~> 0"
|
36
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'keight'
|
4
|
+
require 'baby_erubis'
|
5
|
+
require 'baby_erubis/renderer'
|
6
|
+
|
7
|
+
require './config'
|
8
|
+
|
9
|
+
|
10
|
+
module My
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
class My::Action < K8::Action
|
15
|
+
|
16
|
+
|
17
|
+
##
|
18
|
+
## template
|
19
|
+
##
|
20
|
+
|
21
|
+
include BabyErubis::HtmlEscaper
|
22
|
+
include BabyErubis::Renderer
|
23
|
+
|
24
|
+
ERUBY_PATH = ['app/template']
|
25
|
+
ERUBY_LAYOUT = :_layout
|
26
|
+
ERUBY_HTML = BabyErubis::Html
|
27
|
+
ERUBY_HTML_EXT = '.html.eruby'
|
28
|
+
ERUBY_TEXT = BabyErubis::Text
|
29
|
+
ERUBY_TEXT_EXT = '.eruby'
|
30
|
+
ERUBY_CACHE = {}
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
alias render_html eruby_render_html
|
35
|
+
alias render_text eruby_render_text
|
36
|
+
|
37
|
+
|
38
|
+
##
|
39
|
+
## event handler (= exception handler)
|
40
|
+
##
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
##
|
45
|
+
## Define event handlers here.
|
46
|
+
##
|
47
|
+
## ex:
|
48
|
+
## class Event < Exception; end
|
49
|
+
## class NotExist < Event; end
|
50
|
+
## class NotPermitted < Event; end
|
51
|
+
##
|
52
|
+
## def on_NotExist(ev) # or: define_method "on_Foo::Bar" do |ev|
|
53
|
+
## @resp.status_code = 404 # 404 Not Found
|
54
|
+
## {"error"=>"Not exist"}
|
55
|
+
## end
|
56
|
+
## def on_NotPermitted(ev)
|
57
|
+
## @resp.status_code = 403 # 403 Forbidden
|
58
|
+
## {"error"=>"Not permitted"}
|
59
|
+
## end
|
60
|
+
##
|
61
|
+
## def do_show(id)
|
62
|
+
## item = Item.find(id) or raise NotExist
|
63
|
+
## return {"item"=>{"id"=>id, "name"=>item.name}}
|
64
|
+
## end
|
65
|
+
##
|
66
|
+
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
class My::AdminAction < My::Action
|
72
|
+
|
73
|
+
## override template configs
|
74
|
+
ERUBY_PATH = ['admin/template']
|
75
|
+
ERUBY_LAYOUT = :_admin_layout
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
class My::StaticPage < My::Action
|
81
|
+
|
82
|
+
mapping '/{urlpath:.+}', :GET=>:do_send_file
|
83
|
+
STATIC_DIR = "static"
|
84
|
+
|
85
|
+
def do_send_file(urlpath)
|
86
|
+
filepath = "#{STATIC_DIR}/#{urlpath}"
|
87
|
+
File.file?(filepath) or raise K8::HttpException.new(404)
|
88
|
+
#env = @req.env
|
89
|
+
#header_name = env['sendfile.type'] || env['HTTP_X_SENDFILE_TYPE']
|
90
|
+
#if header_name && ! header_name.empty?
|
91
|
+
# @resp.headers[header_name] = filepath
|
92
|
+
# return nil
|
93
|
+
#else
|
94
|
+
return send_file(filepath)
|
95
|
+
#end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'keight'
|
4
|
+
|
5
|
+
#require_relative '../action'
|
6
|
+
|
7
|
+
|
8
|
+
class HelloAPI < K8::Action # or My::Action
|
9
|
+
|
10
|
+
mapping '' , :GET=>:do_index, :POST=>:do_create
|
11
|
+
mapping '/{id}' , :GET=>:do_show, :PUT=>:do_update, :DELETE=>:do_delete
|
12
|
+
## or if you want support '/hello.json' and '/hello/123.json':
|
13
|
+
#mapping '{ext}' , :GET=>:do_index, :POST=>:do_create
|
14
|
+
#mapping '/{id}{ext}' , :GET=>:do_show, :PUT=>:do_update, :DELETE=>:do_delete
|
15
|
+
|
16
|
+
def do_index()
|
17
|
+
query = @req.params_query # QUERY_STRING
|
18
|
+
{"action"=>"index", "query"=>query}
|
19
|
+
end
|
20
|
+
|
21
|
+
def do_create()
|
22
|
+
form = @req.params_form # or @req.params_json
|
23
|
+
{"action"=>"create", "form"=>form}
|
24
|
+
end
|
25
|
+
|
26
|
+
def do_show(id)
|
27
|
+
{"action"=>"show", "id"=>id}
|
28
|
+
end
|
29
|
+
|
30
|
+
def do_update(id)
|
31
|
+
form = @req.params_form # or @req.params_json
|
32
|
+
{"action"=>"update", "id"=>id, "form"=>form}
|
33
|
+
end
|
34
|
+
|
35
|
+
def do_delete(id)
|
36
|
+
{"action"=>"delete", "id"=>id}
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
File without changes
|
File without changes
|
File without changes
|