keight 0.0.1
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.
- 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
|