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,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ezframe
4
+ class TypeBase
5
+ attr_accessor :attribute, :parent
6
+ attr_writer :value
7
+
8
+ def self.get_class(key)
9
+ return nil unless key
10
+ upper = Object.const_get("Ezframe")
11
+ key_camel = "#{key}_type".to_camel
12
+ # puts "get_class: #{key_camel}"
13
+ # puts "const_get: #{upper.const_get(key_camel).inspect}"
14
+ if upper.const_defined?(key_camel)
15
+ return upper.const_get(key_camel)
16
+ end
17
+ return nil
18
+ end
19
+
20
+ def self.type_name
21
+ if /::(\w*)Type/ =~ to_s
22
+ return $1.to_s.to_snake
23
+ end
24
+ to_s.to_snake
25
+ end
26
+
27
+ def initialize(attr = nil)
28
+ @attribute = attr if attr
29
+ end
30
+
31
+ def key
32
+ @attribute[:key]
33
+ end
34
+
35
+ def label
36
+ return nil if @attribute[:hidden]
37
+ @attribute[:label]
38
+ end
39
+
40
+ def value(_situation = nil)
41
+ @value
42
+ end
43
+
44
+ def view
45
+ @value
46
+ end
47
+
48
+ def db_type
49
+ nil
50
+ end
51
+
52
+ def db_value
53
+ value
54
+ end
55
+
56
+ def form
57
+ nil
58
+ end
59
+ end
60
+
61
+ class StringType < TypeBase
62
+ def normalize
63
+ @value.gsub!(/ /, ' ')
64
+ end
65
+
66
+ def form
67
+ return nil if @attribute[:hidden] && !@attribute[:force]
68
+ { tag: 'input', type: 'text', name: @attribute[:key], key: @attribute[:key], label: @attribute[:label], value: @value }
69
+ end
70
+
71
+ def db_type
72
+ "string"
73
+ end
74
+ end
75
+
76
+ class IntType < StringType
77
+ def view
78
+ return nil if @attribute[:hidden]
79
+ Util.add_comma(@value.to_i)
80
+ end
81
+
82
+ def form
83
+ return nil if @attribute[:hidden]
84
+ { tag: 'input', type: 'number', key: @attribute[:key], label: @attribute[:label], value: @value }
85
+ end
86
+
87
+ def db_type
88
+ "int"
89
+ end
90
+ end
91
+
92
+ class ForeignType < IntType
93
+ def view
94
+ dataset = @parent.db.dataset[self.type.inner]
95
+ data = dataset.get(id: @value)
96
+ data[@attribute[:view]]
97
+ end
98
+ end
99
+
100
+ class IdType < IntType
101
+ def label
102
+ return nil if @attribute[:hidden] && !@attribute[:force]
103
+ "ID"
104
+ end
105
+ end
106
+
107
+ class PasswordType < StringType
108
+ def form
109
+ { tag: "input", type: "password", label: @attribute[:label], value: @value}
110
+ end
111
+
112
+ def db_value
113
+ value
114
+ end
115
+ end
116
+
117
+ class SelectType < TypeBase
118
+ def form
119
+ return nil if @attribute[:hidden]
120
+ { tag: 'select', key: @attribute[:key], label: @attribute[:label], items: @attribute[:items], value: @value }
121
+ end
122
+
123
+ def db_type
124
+ "string"
125
+ end
126
+ end
127
+
128
+ class CheckboxType < TypeBase
129
+ def form
130
+ return nil if @attribute[:hidden]
131
+ { tag: "checkbox", key: @attribute[:key], name: @attribute[:key], value: parent[:id].value, label: @attribute[:label] }
132
+ end
133
+
134
+ def db_type
135
+ "int"
136
+ end
137
+ end
138
+
139
+ class DateType < StringType
140
+ def form
141
+ h = super
142
+ h[:type] = 'date' if h
143
+ h
144
+ end
145
+
146
+ def db_type
147
+ "datetime"
148
+ end
149
+ end
150
+
151
+ class EmailType < StringType
152
+ def form
153
+ h = super
154
+ h[:type] = 'email' if h
155
+ h
156
+ end
157
+ end
158
+
159
+ class TelephoneType < StringType
160
+ def form
161
+ h = super
162
+ h[:type] = 'tel' if h
163
+ h
164
+ end
165
+ end
166
+
167
+ class JpnameType < StringType
168
+ end
169
+
170
+ class JpnameKanaType < StringType
171
+ def set(val)
172
+ val = val.tr('ァ-ン', 'ぁ-ん')
173
+ super(val)
174
+ end
175
+
176
+ def validation
177
+ unless /^[ぁ-ん ]+$/ =~ @value
178
+ 'ひらがなのみで入力してください。'
179
+ end
180
+ end
181
+ end
182
+
183
+ #
184
+ class PrefectureType < SelectType
185
+ def initialize(attr)
186
+ super(attr)
187
+ @pref_a = %w[選択してください 北海道 青森県 岩手県 宮城県 秋田県 山形県 福島県
188
+ 茨城県 栃木県 群馬県 埼玉県 千葉県 東京都 神奈川県
189
+ 新潟県 富山県 石川県 福井県 山梨県 長野県 岐阜県 静岡県 愛知県
190
+ 三重県 滋賀県 京都府 大阪府 兵庫県 奈良県 和歌山県
191
+ 鳥取県 島根県 岡山県 広島県 山口県
192
+ 徳島県 香川県 愛媛県 高知県
193
+ 福岡県 佐賀県 長崎県 熊本県 大分県 宮崎県 鹿児島県 沖縄県]
194
+ @pref_h = {}
195
+ @pref_a.each_with_index { |p, i| @pref_h[i] = p }
196
+ end
197
+
198
+ def form
199
+ h = super
200
+ h[:items] = @pref_h
201
+ h
202
+ end
203
+
204
+ def view
205
+ @pref_h[@value.to_i]
206
+ end
207
+ end
208
+
209
+ # Japanese Zipcode type column
210
+ class ZipcodeType < StringType
211
+ def view
212
+ return "" unless @value
213
+ @value.to_s.gsub(/(\d{3})(\d{4})/) { "#{$1}-#{$2}" }
214
+ end
215
+
216
+ def db_type
217
+ "string"
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,33 @@
1
+ module Ezframe
2
+ class Config
3
+ class << self
4
+ attr_accessor :value_h
5
+
6
+ def load_files(dir)
7
+ Dir["#{dir}/*.yml"].each do |file|
8
+ load_one_file(file)
9
+ end
10
+ end
11
+
12
+ def load_one_file(filename)
13
+ begin
14
+ yaml = YAML.load_file(filename)
15
+ rescue
16
+ mylog("YAML load error: #{filename}")
17
+ return
18
+ end
19
+ @value_h ||={}
20
+ @value_h.update(yaml.recursively_symbolize_keys) if yaml.length>0
21
+ end
22
+
23
+ def [](k)
24
+ @value_h[k] if @value_h
25
+ end
26
+
27
+ def []=(k, v)
28
+ @value_h||={}
29
+ @value_h[k]=v
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ezframe
4
+ class Boot
5
+ class << self
6
+ def exec(request, response)
7
+ @request = request
8
+ Config.load_files("./config")
9
+ Model.init
10
+ model = Model.get_clone
11
+ Auth.init_warden
12
+ Auth.model = model
13
+
14
+ mylog("exec: path=#{request.path_info} params=#{request.params}")
15
+ klass, method = PageBase::decide_route(request.path_info)
16
+ mylog "klass=#{klass}, method=#{method}"
17
+ page = klass.new(request, model)
18
+ if request.post?
19
+ method_full_name = "public_#{method}_post"
20
+ else
21
+ method_full_name = "public_#{method}_page"
22
+ end
23
+ warden.authenticate! if page.auth
24
+ # request.env["rack.session"]["kamatest"]="usable"
25
+ mylog "method: #{klass}.#{method_full_name}"
26
+ mylog "rack.session.id=#{request.env['rack.session'].id}"
27
+ mylog "rack.session.keys=#{request.env['rack.session'].keys}"
28
+ body = if page.respond_to?(method_full_name)
29
+ page.send(method_full_name)
30
+ else
31
+ mylog "no such method: #{method_full_name}"
32
+ page.public_default_page
33
+ end
34
+ if body.is_a?(Hash) || body.is_a?(Array)
35
+ response.body = [ JSON.generate(body) ]
36
+ response['Content-Type'] = 'application/json; charset=utf-8'
37
+ else
38
+ response.body = [ body ]
39
+ response['Content-Type'] = 'text/html; charset=utf-8'
40
+ end
41
+ response.status = 200
42
+ end
43
+
44
+
45
+ def file_not_found(response)
46
+ response.body = ['path not found']
47
+ response.status = 404
48
+ end
49
+
50
+ def warden
51
+ @request.env["warden"]
52
+ end
53
+
54
+ def login?
55
+ !!warden.user
56
+ end
57
+
58
+ def user
59
+ warden.user
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ require "logger"
3
+
4
+ module Ezframe
5
+ class Database
6
+ attr_accessor :sequel
7
+
8
+ def initialize(dbfile = "db/devel.sqlite")
9
+ @dbfile = dbfile
10
+ connect
11
+ end
12
+
13
+ def connect
14
+ @sequel = Sequel.connect("sqlite://#{@dbfile}", loggers: [Logger.new($stdout)])
15
+ end
16
+
17
+ def exec(sql)
18
+ @sequel.run(sql)
19
+ end
20
+
21
+ def dataset(table_name)
22
+ @sequel[table_name.to_sym]
23
+ end
24
+
25
+ def create_table(table_name, dbtype_h)
26
+ %w[id created_at updated_at].each do |key|
27
+ dbtype_h.delete(key.to_sym)
28
+ end
29
+ @sequel.create_table(table_name) do
30
+ primary_key :id, auto_increment: true
31
+ dbtype_h.each do |key, dbtype|
32
+ column(key, dbtype)
33
+ end
34
+ column(:created_at, :timestamp, default: Sequel::CURRENT_TIMESTAMP)
35
+ column(:updated_at, :timestamp, default: Sequel::CURRENT_TIMESTAMP)
36
+ end
37
+ end
38
+
39
+ def insert(table_name, val_h)
40
+ dataset(table_name).insert(val_h)
41
+ end
42
+
43
+ def update(dataset, val_h)
44
+ val_h.update({ updated_at: Time.now() })
45
+ dataset.update(val_h)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,116 @@
1
+ module Ezframe
2
+ module Ht
3
+ class << self
4
+ def wrap_tag(opts = {})
5
+ h = opts.dup
6
+ raise "Ht.wrap_tag: value must be a hash: #{h}" unless h.is_a?(Hash)
7
+ h[:tag] = __callee__.to_s
8
+ h
9
+ end
10
+
11
+ alias_method :h1, :wrap_tag
12
+ alias_method :h2, :wrap_tag
13
+ alias_method :h3, :wrap_tag
14
+ alias_method :h4, :wrap_tag
15
+ alias_method :h5, :wrap_tag
16
+ alias_method :h6, :wrap_tag
17
+ alias_method :p, :wrap_tag
18
+ alias_method :br, :wrap_tag
19
+ alias_method :hr, :wrap_tag
20
+ alias_method :div, :wrap_tag
21
+ alias_method :span, :wrap_tag
22
+ alias_method :i, :wrap_tag
23
+ alias_method :strong, :wrap_tag
24
+ alias_method :ul, :wrap_tag
25
+ alias_method :ol, :wrap_tag
26
+ alias_method :li, :wrap_tag
27
+ alias_method :table, :wrap_tag
28
+ alias_method :thead, :wrap_tag
29
+ alias_method :tbody, :wrap_tag
30
+ alias_method :tr, :wrap_tag
31
+ alias_method :th, :wrap_tag
32
+ alias_method :td, :wrap_tag
33
+ alias_method :img, :wrap_tag
34
+ alias_method :a, :wrap_tag
35
+ alias_method :form, :wrap_tag
36
+ alias_method :button, :wrap_tag
37
+ alias_method :input, :wrap_tag
38
+ alias_method :select, :wrap_tag
39
+ alias_method :textarea, :wrap_tag
40
+ alias_method :label, :wrap_tag
41
+ alias_method :fieldset, :wrap_tag
42
+
43
+ alias_method :icon, :wrap_tag
44
+ alias_method :checkbox, :wrap_tag
45
+ alias_method :radio, :wrap_tag
46
+
47
+ def multi_wrap(class_a, child)
48
+ class_a.reverse.each do |klass|
49
+ child = Ht.div(class: klass, child: child)
50
+ end
51
+ return child
52
+ end
53
+ end
54
+
55
+ class List
56
+ attr_accessor :array
57
+
58
+ def initialize(tag: "ul", array: [])
59
+ @tag = tag
60
+ @array = array.dup
61
+ end
62
+
63
+ def to_hash
64
+ return nil if @list.nil? || @list.empty?
65
+ child = @array.map do |elem|
66
+ { tag: "li", child: elem }
67
+ end
68
+ { tag: @tag, child: child }
69
+ end
70
+ end
71
+
72
+ class Ul < List
73
+ def initialize(array: [])
74
+ super(tag: "ul", array: array)
75
+ end
76
+ end
77
+
78
+ class Ol < List
79
+ def initialize(array: [])
80
+ super(tag: "ol", array: array)
81
+ end
82
+ end
83
+
84
+ class Table
85
+ attr_accessor :class_a, :header
86
+
87
+ def initialize(matrix = nil)
88
+ set(matrix) if matrix
89
+ @matrix ||= []
90
+ end
91
+
92
+ def set(matrix)
93
+ @matrix = matrix
94
+ end
95
+
96
+ def add_row(row)
97
+ @matrix.push(row)
98
+ end
99
+
100
+ def to_hash
101
+ table_class, tr_class, td_class = @class_a
102
+ max_col = 0
103
+ @matrix.each { |row| max_col = row.length if max_col < row.length }
104
+ tr_a = @matrix.map do |row|
105
+ add_attr = nil
106
+ add_attr = { colspan: max_col - row.length + 1 } if row.length < max_col
107
+ td_a = row.map { |v| Ht.td(class: td_class, child: v) }
108
+ td_a[0].update(add_attr) if add_attr
109
+ Ht.tr(class: tr_class, child: td_a)
110
+ end
111
+ tr_a.unshift( Ht.thead(child: Ht.tr(child: @header.map {|v| Ht.th(child: v) }) )) if @header
112
+ Ht.table(class: table_class, child: tr_a)
113
+ end
114
+ end
115
+ end
116
+ end