keight 0.2.0 → 0.3.0

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