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