keight 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +237 -0
  3. data/README.md +285 -81
  4. data/Rakefile +27 -1
  5. data/bench/benchmarker.rb +2 -2
  6. data/bin/k8rb +112 -305
  7. data/keight.gemspec +4 -6
  8. data/lib/keight.rb +860 -822
  9. data/test/keight_test.rb +1007 -933
  10. data/test/oktest.rb +2 -2
  11. metadata +4 -68
  12. data/CHANGES.txt +0 -64
  13. data/lib/keight/skeleton/.gitignore +0 -10
  14. data/lib/keight/skeleton/README.txt +0 -13
  15. data/lib/keight/skeleton/app/action.rb +0 -106
  16. data/lib/keight/skeleton/app/api/hello.rb +0 -39
  17. data/lib/keight/skeleton/app/form/.keep +0 -0
  18. data/lib/keight/skeleton/app/helper/.keep +0 -0
  19. data/lib/keight/skeleton/app/model.rb +0 -144
  20. data/lib/keight/skeleton/app/model/.keep +0 -0
  21. data/lib/keight/skeleton/app/page/welcome.rb +0 -17
  22. data/lib/keight/skeleton/app/template/_layout.html.eruby +0 -56
  23. data/lib/keight/skeleton/app/template/welcome.html.eruby +0 -6
  24. data/lib/keight/skeleton/app/usecase/.keep +0 -0
  25. data/lib/keight/skeleton/config.rb +0 -46
  26. data/lib/keight/skeleton/config.ru +0 -6
  27. data/lib/keight/skeleton/config/app.rb +0 -29
  28. data/lib/keight/skeleton/config/app_dev.rb +0 -8
  29. data/lib/keight/skeleton/config/app_prod.rb +0 -7
  30. data/lib/keight/skeleton/config/app_stg.rb +0 -5
  31. data/lib/keight/skeleton/config/app_test.rb +0 -8
  32. data/lib/keight/skeleton/config/server_puma.rb +0 -22
  33. data/lib/keight/skeleton/config/server_unicorn.rb +0 -21
  34. data/lib/keight/skeleton/config/urlpath_mapping.rb +0 -16
  35. data/lib/keight/skeleton/index.txt +0 -39
  36. data/lib/keight/skeleton/main.rb +0 -22
  37. data/lib/keight/skeleton/static/lib/.keep +0 -0
  38. data/lib/keight/skeleton/test/api/hello_test.rb +0 -27
  39. data/lib/keight/skeleton/test/test_helper.rb +0 -9
data/Rakefile CHANGED
@@ -27,7 +27,7 @@ end
27
27
  desc "run test scripts"
28
28
  task :test do
29
29
  #sh "ruby -r minitest/autorun test/*_test.rb"
30
- sh "ruby test/#{PROJECT}_test.rb"
30
+ sh "ruby test/#{PROJECT}_test.rb -ss"
31
31
  end
32
32
 
33
33
 
@@ -90,3 +90,29 @@ def require_release_number
90
90
  raise StandardError
91
91
  end
92
92
  end
93
+
94
+
95
+ task :http_status_codes do
96
+ require 'open-uri'
97
+ url = "https://en.wikipedia.org/wiki/List_of_HTTP_status_codes"
98
+ content = open(url) {|f| f.read }
99
+ #File.open("/tmp/http_status_code", 'w') {|f| f.write(content) }
100
+ #content = File.open("/tmp/http_status_code", 'rb') {|f| f.read }
101
+ lines = []
102
+ content.scan(/>(\d\d\d)\s+(.*?)<\/dt>/) do |code, text|
103
+ desc = nil
104
+ if text =~ /(.*?)\s+\((.*?)\)/
105
+ text = $1
106
+ desc = $2
107
+ desc = desc.gsub(/<a .*?>(.*?)<\/a>/, '\1')
108
+ end
109
+ text = text.sub(/<\/a>/, '')
110
+ line = " #{code} => \"#{text}\","
111
+ if desc
112
+ line = "%-50s # %s" % [line, desc]
113
+ end
114
+ lines << line
115
+ end
116
+ lines.sort!
117
+ puts lines
118
+ end
@@ -1,5 +1,5 @@
1
1
  ###
2
- ### $Release: 0.2.0 $
2
+ ### $Release: 0.3.0 $
3
3
  ### $Copyright: copyright(c) 2014-2016 kuwata-lab.com all rights reserved $
4
4
  ### $License: MIT License $
5
5
  ###
@@ -7,7 +7,7 @@
7
7
 
8
8
  module Benchmarker
9
9
 
10
- VERSION = "$Release: 0.2.0 $".split(/ /)[1]
10
+ VERSION = "$Release: 0.3.0 $".split(/ /)[1]
11
11
 
12
12
  def self.new(opts={}, &block)
13
13
  #: creates runner object and returns it.
data/bin/k8rb CHANGED
@@ -2,20 +2,55 @@
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
4
  ###
5
- ### $Release: 0.2.0 $
5
+ ### $Release: 0.3.0 $
6
6
  ### $Copyright: copyright(c) 2014-2016 kuwata-lab.com all rights reserved $
7
7
  ### $License: MIT License $
8
8
  ###
9
9
 
10
10
 
11
- require 'keight'
12
- require 'baby_erubis'
11
+ require 'open-uri'
12
+ require 'fileutils'
13
+ require 'json'
13
14
 
14
15
 
15
16
  module K8
16
17
 
17
18
 
18
- class Main
19
+ module ShellHelper
20
+
21
+ def rm_rf(path)
22
+ puts "$ rm -rf #{path}"
23
+ FileUtils.rm_rf path
24
+ end
25
+
26
+ def mv(oldpath, newpath)
27
+ puts "$ mv #{oldpath} #{newpath}"
28
+ File.rename oldpath, newpath
29
+ end
30
+
31
+ def sys(command)
32
+ puts "$ #{command}"
33
+ system command
34
+ end
35
+
36
+ def chdir(dir, &block)
37
+ puts "$ cd #{dir}"
38
+ Dir.chdir(dir, &block)
39
+ puts "$ cd -"
40
+ end
41
+
42
+ def curl_o(filename, url)
43
+ puts "$ curl -o #{filename} \\"
44
+ puts " #{url}"
45
+ data = open(url) {|f| f.read() }
46
+ File.open(filename, 'wb') {|f| f.write(data) }
47
+ end
48
+
49
+ end
50
+
51
+
52
+ class MainApp
53
+ include ShellHelper
19
54
 
20
55
  @__current = nil
21
56
  @__actions = []
@@ -121,245 +156,74 @@ module K8
121
156
  end
122
157
 
123
158
  @action.(:project, "create project files")
124
- @option.("-s, --skeleton=DIR", "directory of skeleton files")
125
159
  def do_project(name, dir: nil)
126
160
  project_name = name
127
- dir ||= K8::FILEPATH.sub(/\.rb\z/, '') + "/skeleton"
128
- if dir
129
- File.directory?(dir) or
130
- raise "#{dir}: directory not exist."
131
- o = K8::FileTool.new
132
- descs = o.parse_index_file("#{dir}/index.txt")
133
- o.mkdir(project_name, "project root directory")
134
- files = Dir.glob("#{dir}/**/*")
135
- files.concat(["#{dir}/.gitignore"])
136
- files.each do |path|
137
- base = path[(dir.length+1)..-1]
138
- if base == "index.txt"
139
- next
140
- elsif base =~ /\/\.keep\z/
141
- next
142
- elsif File.directory?(path)
143
- o.mkdir("#{project_name}/#{base}", descs[base+"/"])
144
- elsif File.file?(path)
145
- content = path =~ /\Astatic\/lib|\.gz\z/ \
146
- ? File.read(path, encoding: 'ascii-8bit') \
147
- : K8::SkeletonTemplate.new.from_file(path, 'ascii-8bit').render()
148
- o.mkfile("#{project_name}/#{base}", content, descs[base])
149
- else
150
- next
151
- end
161
+ ## download zip file
162
+ zip_file = proc {|user, repo|
163
+ json_url = "https://api.github.com/repos/#{user}/#{repo}/releases"
164
+ json_str = open(json_url) {|f| f.read }
165
+ json_arr = JSON.parse(json_str)
166
+ version2intarr = proc {|s| /\d+(\.\d+)*/.match(s)[0].split('.').map(&:to_i) }
167
+ dict = json_arr.max_by {|d| version2intarr.call(d['tag_name']) }
168
+ url = dict['zipball_url']
169
+ puts "## Download boilerplate files"
170
+ file = "#{repo}_#{dict['tag_name']}.zip"
171
+ curl_o(file, url)
172
+ puts ""
173
+ file
174
+ }.call('kwatch', 'keight-ruby-boilerpl8')
175
+ ## unzip it
176
+ proc {|project, zip_file|
177
+ puts "## Extract files"
178
+ destdir = project
179
+ tmpdir = destdir + ".tmp"
180
+ rm_rf destdir if File.exist?(destdir)
181
+ rm_rf tmpdir if File.exist?(tmpdir)
182
+ sys "unzip -d #{tmpdir} -q #{zip_file}"
183
+ paths = Dir.glob("#{tmpdir}/*")
184
+ if paths.length == 1 && File.directory?(paths[0])
185
+ mv paths[0], destdir
186
+ rm_rf tmpdir
187
+ else
188
+ mv tmpdir, destdir
189
+ end
190
+ rm_rf zip_file
191
+ puts ""
192
+ }.call(project_name, zip_file)
193
+ ## run initializer script
194
+ proc {|project|
195
+ puts "## Initialize"
196
+ arrs = [
197
+ ["ruby" , "__init.rb"],
198
+ ["python" , "__init.py"],
199
+ ["bash" , "__init.sh"],
200
+ ]
201
+ destdir = project
202
+ chdir(destdir) do
203
+ command, script = arrs.find {|_, script| File.exist?(script) }
204
+ sys "#{command} #{script}" if script
152
205
  end
153
- #
206
+ puts ""
207
+ }.call(project_name)
208
+ #
209
+ proc {
154
210
  msg = <<-END
155
-
156
211
  ##
157
- ## File copied.
158
- ## Please run 'rake setup' in '#{project_name}' directory, for example:
212
+ ## Project directory created.
213
+ ## Next action:
159
214
  ##
160
215
  ## $ cd #{project_name}
161
- ## $ rake setup
162
216
  ## $ export APP_ENV='dev' # or 'prod', 'stg', 'test'
217
+ ## $ rake -T
163
218
  ## $ rake server port=8000
164
219
  ## $ open http://localhost:8000/
165
220
  ##
166
221
  END
167
- return msg.gsub(/^ /, '')
168
- end
222
+ return msg.gsub(/^\s+/, '')
223
+ }.call
169
224
  0
170
225
  end
171
226
 
172
- @action.(:mapping, "show action mappings")
173
- @option.("--format={text|json|yaml|javascript|jquery|angular}", "output format")
174
- def do_mapping(format: nil)
175
- ENV['APP_MODE'] ||= 'dev'
176
- load_config()
177
- require './config/urlpath_mapping'
178
- return \
179
- case format
180
- when nil ; _do_mapping_in_text_format()
181
- when 'text' ; _do_mapping_in_text_format()
182
- when 'json' ; _do_mapping_in_json_format()
183
- when 'yaml' ; _do_mapping_in_yaml_format()
184
- when 'javascript'; _do_mapping_in_javascript_format(nil)
185
- when 'jquery' ; _do_mapping_in_javascript_format('type')
186
- when 'angular' ; _do_mapping_in_javascript_format('method')
187
- else
188
- raise OptionError.new("#{format}: expected one of text/json/yaml/javascript/jquery/angular.")
189
- end
190
- end
191
-
192
- private
193
-
194
- def _do_mapping(&block)
195
- app = K8::RackApplication.new($urlpath_mapping)
196
- app.each_mapping do |urlpath_pat, action_class, action_methods, |
197
- yield urlpath_pat, action_class, action_methods
198
- end
199
- end
200
- private :_do_mapping
201
-
202
- def _do_mapping_in_json_format()
203
- s = %Q`{ "mappings": [\n`.dup()
204
- i = 0
205
- _do_mapping do |urlpath_pat, action_class, action_methods|
206
- i += 1
207
- arr = action_methods.map {|k, v| %Q`"#{k}": "#{v}"` }
208
- s << (i == 1 ? ' ' : ', ')
209
- s << %Q`{"urlpath": "#{urlpath_pat}"`
210
- s << %Q`, "class": \"#{action_class.name}"`
211
- s << %Q`, "method": {#{arr.join(', ')}}}\n`
212
- end
213
- s << "] }\n"
214
- return s
215
- end
216
-
217
- def _do_mapping_in_yaml_format()
218
- s = ""
219
- _do_mapping do |urlpath_pat, action_class, action_methods|
220
- arr = action_methods.map {|k, v| "#{k}: #{v}" }
221
- s << "- urlpath: '#{urlpath_pat}'\n"
222
- s << " class: #{action_class.name}\n"
223
- s << " method: {#{arr.join(', ')}}\n"
224
- s << "\n"
225
- end
226
- return s
227
- end
228
-
229
- def _do_mapping_in_javascript_format(attr)
230
- rexp = K8::ActionMapping::URLPATH_PARAM_REXP
231
- defs = {}
232
- _do_mapping do |urlpath_pat, action_class, action_methods|
233
- (defs[action_class.name] ||= []) << [urlpath_pat, action_methods]
234
- end
235
- buf = []
236
- defs.each do |action_class_name, pairs|
237
- if action_class_name =~ /\A\w+\z/
238
- buf << "#{action_class_name}:{\n"
239
- else
240
- buf << "'#{action_class_name}':{\n"
241
- end
242
- sep = ' '
243
- pairs.each do |urlpath_pat, action_methods|
244
- args = []; i = 0
245
- urlpath_pat.scan(rexp) {|x, _| args << (x.empty? ? "_#{i+=1}" : x) }
246
- a = args.dup()
247
- js_urlpath = "'" + urlpath_pat.gsub(rexp) {|x, _| "'+#{a.shift}+'" } + "'"
248
- js_urlpath.gsub!(/\+''/, '')
249
- #
250
- action_methods.each do |req_meth, action_method|
251
- buf << sep; sep = ','
252
- if attr
253
- js_code = "return{#{attr}:'#{req_meth}',url:#{js_urlpath}}"
254
- buf << "#{action_method}:function(#{args.join(',')}){#{js_code}}\n"
255
- else
256
- js_code = "function(#{args.join(',')}){return#{js_urlpath}}"
257
- buf << "#{action_method}:{method:'#{req_meth}',urlpath:#{js_code}}\n"
258
- end
259
- end
260
- end
261
- buf << "},\n"
262
- end
263
- buf[-1] = "}\n" if buf[-1] == "},\n"
264
- return buf.join()
265
- end
266
-
267
- def _do_mapping_in_text_format()
268
- s = ""
269
- _do_mapping do |urlpath_pat, action_class, action_methods|
270
- action_methods.each do |req_meth, action_method|
271
- s << "%-6s %-30s # %s\#%s\n" % [req_meth, urlpath_pat, action_class.name, action_method]
272
- end
273
- end
274
- return s
275
- end
276
-
277
- public
278
-
279
- @action.(:configs, "list config keys and values")
280
- @option.("--getenv", "show actual ENV value")
281
- def do_configs(getenv: false)
282
- ENV['APP_MODE'] ||= 'dev'
283
- load_config()
284
- s = ""
285
- ::Config.each do |key, val, desc, secret|
286
- kv = "%-20s = %s" % [key, __var_dump(val, secret, getenv)]
287
- s << ("%-43s # %s\n" % [kv, desc]) if desc
288
- end
289
- return s
290
- end
291
-
292
- @action.(:config, "show config value")
293
- @option.("--getenv", "show actual ENV value")
294
- def do_config(key, getenv: false)
295
- key_name = key
296
- ENV['APP_MODE'] ||= 'dev'
297
- load_config()
298
- ::Config.each do |key, val, desc, secret|
299
- if key.to_s == key_name
300
- return __var_dump(val, secret, getenv)
301
- end
302
- end
303
- $stderr.puts "#{key_name}: no such config key."
304
- return 1
305
- end
306
-
307
- @action.(:'config:check', "check config values")
308
- def do_config_check()
309
- ENV['APP_MODE'] ||= 'dev'
310
- load_config()
311
- not_set = []
312
- not_env = []
313
- ::Config.each do |key, val, desc, secret|
314
- if val.is_a?(K8::SecretValue)
315
- if ! val.name
316
- not_set << [key, val, desc]
317
- elsif ! ENV[val.name]
318
- not_env << [key, val, desc]
319
- end
320
- end
321
- end
322
- if not_set.empty? && not_env.empty?
323
- puts "ok."
324
- return 0
325
- else
326
- sb = []
327
- sb << "**"
328
- sb << "** NG!"
329
- unless not_set.empty?
330
- sb << "**"
331
- sb << "** The following configs should be set, but not."
332
- sb << "**"
333
- not_set.each do |key, val, desc|
334
- sb << "** %-20s = %s" % [key, val.inspect]
335
- end
336
- end
337
- unless not_env.empty?
338
- sb << "**"
339
- sb << "** The following configs expect environment variable, but not set."
340
- sb << "**"
341
- not_env.each do |key, val, desc|
342
- sb << "** %-20s = %s" % [key, val.inspect]
343
- end
344
- end
345
- sb << "**"
346
- puts sb.join("\n")
347
- return 1
348
- end
349
- end
350
-
351
- def __var_dump(val, secret, getenv)
352
- if ! val.is_a?(K8::SecretValue)
353
- #secret ? '<secret>' : val.inspect
354
- val.inspect
355
- elsif val.name
356
- getenv ? ENV[val.name].inspect : "ENV['#{val.name}']"
357
- else
358
- '<SECRET>'
359
- end
360
- end
361
- private :__var_dump
362
-
363
227
  @action.(:cdnjs, "search or download libraries from cdnjs.com")
364
228
  @option.("-d, --basedir=DIR", "base directory (default: 'static/lib')")
365
229
  def do_cdnjs(library=nil, version=nil, basedir: nil)
@@ -382,12 +246,10 @@ module K8
382
246
  end
383
247
 
384
248
  def _cdnjs_list(pattern)
385
- url = "https://cdnjs.com/libraries"
386
- rexp = %r'href="/libraries/([-.\w]+)"'
387
- libs = open(url) {|f|
388
- #f.grep(rexp) { $1 } # not work
389
- f.collect {|s| $1 if s =~ rexp }.compact.sort.uniq
390
- }
249
+ url = "https://api.cdnjs.com/libraries"
250
+ json_str = open(url) {|f| f.read() }
251
+ json_dict = JSON.parse(json_str)
252
+ libs = json_dict['results'].collect {|d| d['name'] }
391
253
  if pattern
392
254
  s = Regexp.escape(pattern) # ex: '*foo.js*' -> '\*foo\.js\*'
393
255
  s = s.gsub(/\\\*/, '.*') # ex: '\*foo\.js\*' -> '.*foo\.js.*'
@@ -399,11 +261,12 @@ module K8
399
261
  end
400
262
 
401
263
  def _cdnjs_find(library)
402
- url = "https://cdnjs.com/libraries/#{library}"
403
- rexp = %r'<option value="(.*?)".*?>\1</option>'
404
- versions = open(url) {|f|
405
- f.collect {|s| $1 if s =~ rexp }.compact()
406
- }.sort_by {|verstr| _normalized_version(verstr) }
264
+ url = "https://api.cdnjs.com/libraries/#{library}"
265
+ json_str = open(url) {|f| f.read }
266
+ json_dict = JSON.parse(json_str)
267
+ versions = (json_dict["assets"] || []) \
268
+ .collect {|d| d["version"] } \
269
+ .sort_by {|verstr| _normalized_version(verstr) }
407
270
  if versions.empty?
408
271
  $stderr.puts "#{library}: no such library (GET #{url})."
409
272
  return 1
@@ -412,17 +275,19 @@ module K8
412
275
  end
413
276
 
414
277
  def _cdnjs_download(library, version, basedir=nil)
278
+ option_d_specified = !! basedir
415
279
  basedir ||= "static/lib"
416
280
  File.exist?(basedir) or
417
- raise OptionError.new("#{basedir}: directory not exist.")
281
+ raise OptionError.new("#{basedir}: directory not exist" +
282
+ (option_d_specified ? "." : " (try '-d' to specify location)."))
418
283
  File.directory?(basedir) or
419
284
  raise OptionError.new("#{basedir}: not a directory.")
420
- url = "https://cdnjs.com/libraries/#{library}/#{version}"
421
- rexp = %r">https://cdnjs\.cloudflare\.com/ajax/libs/#{library}/#{Regexp.escape(version)}/([-.\w]+(?:\&\#x2F;[-.\w]+)*)<"
422
- filenames = open(url) {|f|
423
- f.collect {|s| $1.gsub(/\&\#x2F;/, '/') if s =~ rexp }.compact()
424
- }
425
- if filenames.empty?
285
+ url = "https://api.cdnjs.com/libraries/#{library}"
286
+ json_str = open(url) {|f| f.read() }
287
+ json_dict = JSON.parse(json_str)
288
+ asset = json_dict["assets"].find {|d| d["version"] == version } || {}
289
+ filenames = asset["files"] # ex: ["jquery.js", "jquery.min.js"]
290
+ if filenames.nil? || filenames.empty?
426
291
  $stderr.puts "#{library} #{version}: no files (GET #{url})."
427
292
  return 1
428
293
  end
@@ -492,10 +357,6 @@ module K8
492
357
 
493
358
  ###
494
359
 
495
- def load_config
496
- require './config' rescue K8::ConfigError
497
- end
498
-
499
360
  def run(*cmd_args)
500
361
  action_name = cmd_args.shift() || 'help'
501
362
  tuple = self.class.find_action(action_name) or
@@ -651,63 +512,9 @@ module K8
651
512
  end
652
513
 
653
514
 
654
- class SkeletonTemplate < BabyErubis::Text
655
-
656
- rexp = BabyErubis::Text::PATTERN
657
- PATTERN = Regexp.compile(rexp.to_s.sub(/<%/, '\{%').sub(/%>/, '%\}'))
658
-
659
- def pattern
660
- PATTERN
661
- end
662
-
663
- end
664
-
665
-
666
- class FileTool
667
-
668
- def initialize(width: 30)
669
- @width = width
670
- @depth = 0
671
- end
672
-
673
- def parse_index_file(index_file)
674
- dict = File.open(index_file) {|f|
675
- f.grep(/^[^#]/).each_with_object({}) {|line, d|
676
- path, desc = line.chomp.split(/\s+/, 2)
677
- d[path] = desc
678
- }
679
- }
680
- return dict
681
- end
682
-
683
- def report(s, desc)
684
- indent = ' ' * @depth
685
- puts "%s%-#{@width - indent.length}s # %s" % [indent, s, desc]
686
- end
687
-
688
- def mkrootdir(dirpath)
689
- @root = dirpath
690
- mkdir(dirpath)
691
- end
692
-
693
- def mkdir(dirpath, desc)
694
- Dir.mkdir dirpath
695
- s = dirpath.gsub(/.*?[\/\\]/, ' ') + "/"
696
- report(s, desc)
697
- end
698
-
699
- def mkfile(filepath, content, desc)
700
- File.open(filepath, 'wb') {|dst| dst.write(content) }
701
- s = filepath.gsub(/.*?[\/\\]/, ' ')
702
- report(s, desc)
703
- end
704
-
705
- end
706
-
707
-
708
515
  end
709
516
 
710
517
 
711
518
  #if __FILE__ == $0
712
- K8::Main.main() unless defined? NOEXEC_SCRIPT
519
+ K8::MainApp.main() unless defined? NOEXEC_SCRIPT
713
520
  #end