ezframe 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rubocop.yml +44 -0
  4. data/Gemfile +5 -0
  5. data/README.md +37 -0
  6. data/Rakefile +6 -0
  7. data/example/auth/Gemfile +8 -0
  8. data/example/auth/asset/css/materialize.min.css +13 -0
  9. data/example/auth/asset/js/common.js +200 -0
  10. data/example/auth/asset/js/htmlgen.js +79 -0
  11. data/example/auth/columns/user.yml +12 -0
  12. data/example/auth/config.ru +26 -0
  13. data/example/auth/config/view_conf.yml +3 -0
  14. data/example/auth/pages/app.rb +61 -0
  15. data/example/auth/template/base.html +12 -0
  16. data/example/chat/Gemfile +9 -0
  17. data/example/chat/asset/css/materialize.min.css +13 -0
  18. data/example/chat/asset/js/common.js +200 -0
  19. data/example/chat/asset/js/htmlgen.js +79 -0
  20. data/example/chat/columns/belong.yml +6 -0
  21. data/example/chat/columns/channel.yml +3 -0
  22. data/example/chat/columns/talk.yml +6 -0
  23. data/example/chat/columns/user.yml +12 -0
  24. data/example/chat/config.ru +23 -0
  25. data/example/chat/config/view_conf.yml +3 -0
  26. data/example/chat/pages/app.rb +59 -0
  27. data/example/chat/template/base.html +12 -0
  28. data/example/todo/Gemfile +8 -0
  29. data/example/todo/asset/css/datatable.css +54 -0
  30. data/example/todo/asset/css/materialize.min.css +13 -0
  31. data/example/todo/asset/js/common.js +135 -0
  32. data/example/todo/asset/js/datatable.js +1814 -0
  33. data/example/todo/asset/js/htmlgen.js +79 -0
  34. data/example/todo/asset/js/init.js +3 -0
  35. data/example/todo/asset/js/materialize.min.js +6 -0
  36. data/example/todo/asset/js/mydatatable.js +9 -0
  37. data/example/todo/asset/js/mymaterialize.js +22 -0
  38. data/example/todo/columns/todo.yml +9 -0
  39. data/example/todo/config.ru +15 -0
  40. data/example/todo/config/view_conf.yml +3 -0
  41. data/example/todo/pages/app.rb +93 -0
  42. data/example/todo/template/base.html +12 -0
  43. data/exe/console +14 -0
  44. data/exe/create_table.rb +11 -0
  45. data/exe/myrackup +5 -0
  46. data/ezframe.gemspec +43 -0
  47. data/lib/ezframe.rb +28 -0
  48. data/lib/ezframe/auth.rb +68 -0
  49. data/lib/ezframe/column_set.rb +174 -0
  50. data/lib/ezframe/column_type.rb +220 -0
  51. data/lib/ezframe/config.rb +33 -0
  52. data/lib/ezframe/controller.rb +63 -0
  53. data/lib/ezframe/database.rb +48 -0
  54. data/lib/ezframe/hthash.rb +116 -0
  55. data/lib/ezframe/html.rb +84 -0
  56. data/lib/ezframe/materialize.rb +109 -0
  57. data/lib/ezframe/model.rb +54 -0
  58. data/lib/ezframe/page_base.rb +109 -0
  59. data/lib/ezframe/page_kit.rb +84 -0
  60. data/lib/ezframe/pages.rb +8 -0
  61. data/lib/ezframe/server.rb +15 -0
  62. data/lib/ezframe/template.rb +25 -0
  63. data/lib/ezframe/util.rb +86 -0
  64. data/lib/ezframe/version.rb +3 -0
  65. metadata +236 -0
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ezframe
4
+ class Html
5
+ class << self
6
+ def convert(ht_h = {})
7
+ return "" if ht_h.nil? || ht_h.to_s.empty?
8
+ return ht_h.to_html if ht_h.respond_to?(:to_html)
9
+ return ht_h.to_s if ht_h.is_a?(String) || ht_h.is_a?(Symbol) || ht_h.is_a?(Integer) || ht_h.is_a?(Time)
10
+ return ht_h.map { |args| convert(args) }.join if ht_h.is_a?(Array)
11
+
12
+ tag = ht_h[:tag]
13
+ case tag
14
+ when "select"
15
+ return select(ht_h) if ht_h[:items]
16
+ when "icon"
17
+ tag = "i"
18
+ end
19
+ opt_s, child_s = join_attributes(ht_h)
20
+ if child_s.length.positive?
21
+ return "<#{tag} #{opt_s}>\n#{child_s}\n</#{tag}>\n"
22
+ end
23
+ "<#{tag} #{opt_s}/>"
24
+ end
25
+
26
+ def join_attributes(attrs)
27
+ child_s = ""
28
+ opt_a = attrs.map do |k, v|
29
+ case k
30
+ when :child
31
+ child_s = convert(v)
32
+ next
33
+ when :tag, :final
34
+ next
35
+ when :key
36
+ "name=\"#{v}\"" if attrs[:tag].to_sym == :input
37
+ next
38
+ else
39
+ if v.is_a?(Array)
40
+ "#{k}=\"#{v.join(" ")}\""
41
+ elsif v.nil?
42
+ nil
43
+ else
44
+ "#{k}=\"#{v}\""
45
+ end
46
+ end
47
+ end
48
+ [opt_a.compact.join(" "), child_s]
49
+ end
50
+
51
+ def select(ht_h = {})
52
+ attr = ht_h.clone
53
+ items = attr[:items]
54
+ if items.is_a?(Hash)
55
+ option_a = ht_h[:items].map do |k, v|
56
+ h = { tag: "option", value: k }
57
+ if v.is_a?(Array)
58
+ v, selected = v
59
+ h[:selected] = "selected" if selected
60
+ end
61
+ h[:child] = v
62
+ h
63
+ end
64
+ elsif items.is_a?(Array)
65
+ option_a = items.map do |v|
66
+ h = { tag: "option", value: v[0], child: v[1] }
67
+ if %w[selected default].include?(v[2])
68
+ h[:selected] = "selected"
69
+ end
70
+ h
71
+ end
72
+ else
73
+ warn "unknown items: #{ht_h.inspect}"
74
+ end
75
+ attr[:tag] = "select"
76
+ attr[:child] = option_a
77
+ attr[:name] = attr[:key]
78
+ attr[:final] = true
79
+ attr.delete(:items)
80
+ Html.convert(attr)
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ezframe
4
+ class Materialize
5
+ class << self
6
+ def into_html_header
7
+ str =<<~EOHEAD2
8
+ <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
10
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
11
+ EOHEAD2
12
+
13
+ css_files = Dir["./asset/css/*.css"]||[]
14
+ css_a = css_files.map do |file|
15
+ file.gsub!("./asset", "")
16
+ "<link href=\"#{file}\" rel=\"stylesheet\">\n"
17
+ end
18
+ js_files = Dir["./asset/js/*.js"]||[]
19
+ js_a = js_files.map do |file|
20
+ file.gsub!("./asset", "")
21
+ "<script src=\"#{file}\"></script>\n"
22
+ end
23
+ str+(css_a+js_a).join
24
+ end
25
+
26
+ def into_bottom_of_body
27
+ ""
28
+ # Dir["./asset/js"].each do ||
29
+ # <<~EOBOT
30
+ # <script src="/js/htmlgen.js"></script>
31
+ # <script src="/js/common.js"></script>
32
+ # EOBOT
33
+ end
34
+
35
+ def convert(ht_h)
36
+ return nil unless ht_h
37
+ return ht_h if (ht_h.kind_of?(Hash) && ht_h[:final])
38
+ new_h = ht_h.clone
39
+ if ht_h.kind_of?(Array)
40
+ new_h = ht_h.map { |v| convert(v) }
41
+ elsif ht_h.kind_of?(Hash)
42
+ case ht_h[:tag].to_sym
43
+ when :input, :select
44
+ new_h = input(ht_h) if "hidden" != ht_h[:type]
45
+ return new_h
46
+ when :checkbox
47
+ return checkbox(ht_h)
48
+ when :radio
49
+ return radio(ht_h)
50
+ when :icon
51
+ return icon(ht_h)
52
+ when :form
53
+ return new_h = form(ht_h)
54
+ when :table
55
+ new_h.add_class(%w[striped highlight])
56
+ end
57
+ new_h[:child] = convert(ht_h[:child]) if ht_h[:child]
58
+ end
59
+ return new_h
60
+ end
61
+
62
+ def icon(ht_h)
63
+ new_h = ht_h.clone
64
+ mylog "[warn] no name attribute for icon ht_h: #{ht_h.inspect}" unless new_h[:name]
65
+ new_h.add_class("material-icons")
66
+ new_h.update({ tag: "i", child: ht_h[:name] })
67
+ new_h.delete(:name)
68
+ return new_h
69
+ end
70
+
71
+ def form(ht_h)
72
+ new_h = ht_h.clone
73
+ new_h[:child] = convert(new_h[:child])
74
+ return new_h
75
+ end
76
+
77
+ def input(ht_h)
78
+ ht_h[:name] ||= ht_h[:key]
79
+ width_s = "s#{ht_h[:width_s] || 12}"
80
+ ht_h.delete(:witdth_s)
81
+ label = Ht.label(for: ht_h[:key], child: ht_h[:label], final: true )
82
+ cls = ["input-field", "col", width_s]
83
+ new_h = Ht.div(class: cls, child: [ht_h, label])
84
+ new_h = Ht.div(child: new_h, class: "row")
85
+ return new_h
86
+ end
87
+
88
+ def checkbox(ht_h)
89
+ ht_h[:tag] = "input"
90
+ ht_h[:type] = "checkbox"
91
+ Ht.label(child: [ht_h, { tag: "span", child: ht_h[:value] }])
92
+ end
93
+
94
+ def radio(ht_h)
95
+ ht_h[:tag] = "input"
96
+ ht_h[:type] = "radio"
97
+ Ht.label(child: [ht_h, { tag: "span", child: ht_h[:label] }])
98
+ end
99
+
100
+ def add_sibling(dest, elem)
101
+ if dest.is_a?(Array)
102
+ dest.push(elem)
103
+ else
104
+ [dest, elem]
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+
5
+ module Ezframe
6
+ class Model
7
+ class << self
8
+
9
+ def init_column_sets
10
+ @base_column_sets = ColumnSets.new
11
+ @base_column_sets.load_files('./columns')
12
+ end
13
+
14
+ def init_db
15
+ @base_db = Database.new
16
+ end
17
+
18
+ def init
19
+ unless @base_column_sets
20
+ init_column_sets
21
+ init_db
22
+ end
23
+ end
24
+
25
+ def get_clone
26
+ new(@base_column_sets.deep_dup, @base_db)
27
+ end
28
+ end
29
+
30
+ attr_accessor :column_sets, :db
31
+
32
+ def initialize(column_sets, db)
33
+ @column_sets, @db = column_sets, db
34
+ @column_sets.model = self
35
+ # @column_sets.each {|name, colset| colset.model = self }
36
+ end
37
+
38
+ def create_tables
39
+ @column_sets.tables.each do |table_name, column_set|
40
+ begin
41
+ create_one_table(table_name, column_set)
42
+ rescue => e
43
+ mylog("*** #{e.inspect}\n#{$@.inspect}")
44
+ end
45
+ end
46
+ end
47
+
48
+ def create_one_table(table_name, column_set)
49
+ col_h = column_set.get_hash(:db_type)
50
+ mylog "create_one_table: col_h=#{col_h.inspect}"
51
+ @db.create_table(table_name, col_h)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "uri"
5
+
6
+ require_relative "util"
7
+
8
+ module Ezframe
9
+ class PageBase
10
+ class << self
11
+ def get_class(keys)
12
+ keys = [keys] if keys.is_a?(String)
13
+ klass = (%w[Ezframe] + keys.map { |k| k.to_camel }).join("::")
14
+ if Object.const_defined?(klass)
15
+ return Object.const_get(klass)
16
+ end
17
+ return nil
18
+ end
19
+
20
+ def decide_route(path_info)
21
+ default_class = Config[:default_page_class]||"App"
22
+ default_method = Config[:default_page_method]||"default"
23
+ path_parts = path_info.split('/').drop(1)
24
+ case path_parts.length
25
+ when 0
26
+ [get_class(default_class), default_method]
27
+ when 1
28
+ klass = get_class(path_parts)
29
+ if klass
30
+ return [klass, default_method]
31
+ else
32
+ return [get_class(default_class), parth_parts[0]]
33
+ end
34
+ else
35
+ klass = get_class(path_parts)
36
+ if klass
37
+ [klass, default_method]
38
+ else
39
+ method = path_parts.pop
40
+ klass = get_class(path_parts)
41
+ [klass, method]
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ attr_accessor :auth
48
+
49
+ def initialize(request = nil, model = nil)
50
+ @model = model if model
51
+ if request
52
+ @request = request
53
+ @params = parse_query_string(request.env["QUERY_STRING"])
54
+ @params.update(request.params)
55
+ mylog "params=#{@params.inspect}" if @params.length > 0
56
+ @id, @key = @params[:id], @params[:key]
57
+ @env = @request.env
58
+ @session = @env["rack.x-session"]
59
+ if request.post?
60
+ parse_json_body
61
+ mylog "json=#{@json.inspect}"
62
+ end
63
+ end
64
+ @auth = nil
65
+ end
66
+
67
+ def parse_query_string(str)
68
+ query_a = URI::decode_www_form(str)
69
+ res_h = {}
70
+ query_a.map { |a| res_h[a[0].to_sym] = a[1] }
71
+ res_h
72
+ end
73
+
74
+ def common_page(opts = {})
75
+ args = {
76
+ title: opts[:title],
77
+ body: opts[:body],
78
+ into_html_header: Materialize.into_html_header,
79
+ into_bottom_of_body: Materialize.into_bottom_of_body,
80
+ }
81
+ EzView::Template.fill_template("template/base.html", args)
82
+ end
83
+
84
+ def parse_json_body
85
+ body = @request.body.read
86
+ return {} if !body || body.length==0
87
+ begin
88
+ @json = JSON.parse(body)
89
+ rescue => e
90
+ mylog "ERROR: #{e.class}:#{e.message}\n#{e.backtrace}"
91
+ return nil
92
+ end
93
+ @json = @json.recursively_symbolize_keys if @json.is_a?(Hash) || @json.is_a?(Array)
94
+ return @json
95
+ end
96
+
97
+ def warden
98
+ @request.env["warden"]
99
+ end
100
+
101
+ def login?
102
+ !!warden.user
103
+ end
104
+
105
+ def user
106
+ warden.user
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ezframe
4
+ module PageKit
5
+ class IndexTable
6
+ def initialize(attr = {})
7
+ @attribute = attr
8
+ end
9
+
10
+ def make_table(row_a)
11
+ column_set = @attribute[:column_set]
12
+ table_a = row_a.map do |row_h|
13
+ column_set.values = row_h
14
+ id = column_set[:id].value
15
+ value_a = @attribute[:column_header].map do |key|
16
+ col = column_set[key]
17
+ checkbox_key = @attribute[:add_checkbox]
18
+ if checkbox_key && key == checkbox_key
19
+ text = add_checkbox(col)
20
+ else
21
+ text = col.view
22
+ end
23
+ deco = @attribute[:decorate_column]
24
+ if deco
25
+ text = deco.call(key, id, text)
26
+ # mylog "deco: #{text}"
27
+ end
28
+ td = { tag: "td", child: text }
29
+ # td.update(@attribute[:onclick_rows].call(id, text)) if @attribute[:onclick_rows]
30
+ td
31
+ end
32
+ tr = { tag: "tr", child: value_a }
33
+ if @attribute[:onclick_rows]
34
+ tr[:id] = elem_id = "tr_#{id}"
35
+ # tr.update(@attribute[:onclick_rows].call(id))
36
+ end
37
+ tr
38
+ end
39
+ { tag: "table", child: [make_header, table_a] }
40
+ end
41
+
42
+ def add_checkbox(col)
43
+ { tag: "checkbox", name: "checkbox_#{col.key}_#{col.value}", value: col.value, label: col.view }
44
+ end
45
+
46
+ def make_header
47
+ column_set = @attribute[:column_set]
48
+ th_a = @attribute[:column_header].map do |key|
49
+ col = column_set[key]
50
+ if col
51
+ { tag: "th", child: col.label }
52
+ else
53
+ nil
54
+ end
55
+ end
56
+ if @attribute[:add_checkbox]
57
+ end
58
+ { tag: "tr", child: th_a }
59
+ end
60
+ end
61
+
62
+ class Tab
63
+ def self.base_hthash(link_list)
64
+ size = 12 / link_list.length
65
+ tabs = link_list.map do |link|
66
+ { tag: "li", class: ["tab", "s#{size}"], child: link }
67
+ end
68
+ ul = { tag: "ul", class: %w[tabs], child: tabs }
69
+ div = { tag: "div", class: %w[row s12], child: ul }
70
+ { tag: "div", class: %w[row], child: div }
71
+ end
72
+ end
73
+
74
+ class Card
75
+ def self.base_hthash(title: "", content: "")
76
+ multi_div([%w[row], %w[col s12], %w[card blue-grey darken-1], %w[card-content white-text]],
77
+ [
78
+ { tag: "span", class: %w[card-tite], child: title },
79
+ { tag: "p", child: content },
80
+ ])
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ if File.exist?("pages/common.rb")
4
+ require "#{Dir.pwd}/pages/common.rb"
5
+ end
6
+ Dir["pages/*.rb"].each do |file|
7
+ require "#{Dir.pwd}/#{file}"
8
+ end