waxx 0.1.2

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 (75) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/LICENSE +201 -0
  4. data/README.md +879 -0
  5. data/bin/waxx +120 -0
  6. data/lib/waxx/app.rb +173 -0
  7. data/lib/waxx/conf.rb +54 -0
  8. data/lib/waxx/console.rb +204 -0
  9. data/lib/waxx/csrf.rb +14 -0
  10. data/lib/waxx/database.rb +80 -0
  11. data/lib/waxx/encrypt.rb +38 -0
  12. data/lib/waxx/error.rb +60 -0
  13. data/lib/waxx/html.rb +33 -0
  14. data/lib/waxx/http.rb +268 -0
  15. data/lib/waxx/init.rb +273 -0
  16. data/lib/waxx/irb.rb +44 -0
  17. data/lib/waxx/irb_env.rb +18 -0
  18. data/lib/waxx/json.rb +23 -0
  19. data/lib/waxx/mongodb.rb +221 -0
  20. data/lib/waxx/mysql2.rb +234 -0
  21. data/lib/waxx/object.rb +115 -0
  22. data/lib/waxx/patch.rb +138 -0
  23. data/lib/waxx/pdf.rb +69 -0
  24. data/lib/waxx/pg.rb +246 -0
  25. data/lib/waxx/process.rb +270 -0
  26. data/lib/waxx/req.rb +116 -0
  27. data/lib/waxx/res.rb +98 -0
  28. data/lib/waxx/server.rb +304 -0
  29. data/lib/waxx/sqlite3.rb +237 -0
  30. data/lib/waxx/supervisor.rb +47 -0
  31. data/lib/waxx/test.rb +162 -0
  32. data/lib/waxx/util.rb +57 -0
  33. data/lib/waxx/version.rb +3 -0
  34. data/lib/waxx/view.rb +389 -0
  35. data/lib/waxx/waxx.rb +73 -0
  36. data/lib/waxx/x.rb +103 -0
  37. data/lib/waxx.rb +50 -0
  38. data/skel/README.md +11 -0
  39. data/skel/app/app/app.rb +39 -0
  40. data/skel/app/app/error/app_error.rb +16 -0
  41. data/skel/app/app/error/dhtml.rb +9 -0
  42. data/skel/app/app/error/html.rb +8 -0
  43. data/skel/app/app/error/json.rb +8 -0
  44. data/skel/app/app/error/pdf.rb +13 -0
  45. data/skel/app/app/log/app_log.rb +13 -0
  46. data/skel/app/app.rb +20 -0
  47. data/skel/app/home/home.rb +16 -0
  48. data/skel/app/home/html.rb +145 -0
  49. data/skel/app/html.rb +192 -0
  50. data/skel/app/usr/email.rb +66 -0
  51. data/skel/app/usr/html.rb +115 -0
  52. data/skel/app/usr/list.rb +51 -0
  53. data/skel/app/usr/password.rb +54 -0
  54. data/skel/app/usr/record.rb +98 -0
  55. data/skel/app/usr/usr.js +67 -0
  56. data/skel/app/usr/usr.rb +277 -0
  57. data/skel/app/waxx/waxx.rb +109 -0
  58. data/skel/bin/README.md +1 -0
  59. data/skel/db/README.md +11 -0
  60. data/skel/db/app/0-init.sql +88 -0
  61. data/skel/lib/README.md +1 -0
  62. data/skel/log/README.md +1 -0
  63. data/skel/opt/dev/config.yaml +1 -0
  64. data/skel/opt/prod/config.yaml +1 -0
  65. data/skel/opt/stage/config.yaml +1 -0
  66. data/skel/opt/test/config.yaml +1 -0
  67. data/skel/private/README.md +1 -0
  68. data/skel/public/lib/site.css +202 -0
  69. data/skel/public/lib/waxx/w.ico +0 -0
  70. data/skel/public/lib/waxx/w.png +0 -0
  71. data/skel/public/lib/waxx/waxx.js +111 -0
  72. data/skel/tmp/pids/README.md +1 -0
  73. data.tar.gz.sig +0 -0
  74. metadata +140 -0
  75. metadata.gz.sig +3 -0
data/lib/waxx/json.rb ADDED
@@ -0,0 +1,23 @@
1
+ # Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
2
+ # Released under the Apache Version 2 License. See LICENSE.txt.
3
+
4
+ module Waxx::Json
5
+ extend self
6
+ def get(x, d, message:{})
7
+ if PG::Result === d
8
+ x << d.map{|r| r}.to_json
9
+ else
10
+ x << d.to_json
11
+ end
12
+ end
13
+ alias :post :get
14
+ alias :put :get
15
+ alias :patch :get
16
+ def delete(x, message:{})
17
+ x << {ok: true, type: message[:type], message: message[:message]}.to_json
18
+ end
19
+ def not_found(x, data:{}, message:{})
20
+ x.res.status = 404
21
+ x << {ok: false, type: message[:type], message: message[:message]}.to_json
22
+ end
23
+ end
@@ -0,0 +1,221 @@
1
+ # Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
2
+ # Released under the Apache Version 2 License. See LICENSE.txt.
3
+
4
+ module Waxx::Mongodb
5
+
6
+ attr :db
7
+ attr :table
8
+ attr :columns
9
+ attr :pkey
10
+ attr :joins
11
+ attr :orders
12
+
13
+ def init(db:"app", table:nil, pk:"id", cols:nil)
14
+ @db = db.to_sym
15
+ @table = (table || App.table_from_class(name)).to_sym
16
+ @pkey = pk.to_sym
17
+ @columns = {}
18
+ @joins = {}
19
+ @orders = {}
20
+ has(cols) if cols
21
+ end
22
+
23
+ def has(opts=nil)
24
+ init if @table.nil?
25
+ return @columns if opts.nil?
26
+ @columns = opts
27
+ @columns.each{|n,v|
28
+ v[:table] = @table
29
+ v[:column] = n
30
+ v[:views] = []
31
+ v[:label] ||= Waxx::Util.label(n)
32
+ @orders[n] = v[:order] || n
33
+ @orders["_#{n}".to_sym] = v[:_order] || "#{n} DESC"
34
+ @pkey = n if v[:pkey]
35
+ if v[:is]
36
+ r, tc = v[:is].split(":")
37
+ t, c = tc.split(".")
38
+ @joins[r] = {join: "INNER", table: t, col: c}
39
+ end
40
+ if v[:has]
41
+ r, tc = v[:has].split(":")
42
+ t, c = tc.split(".")
43
+ @joins[r] = {join: "LEFT", table: t, col: c}
44
+ end
45
+ }
46
+ end
47
+
48
+ def [](n)
49
+ @columns[n.to_sym]
50
+ end
51
+
52
+ def /(n)
53
+ @columns[n.to_sym]
54
+ end
55
+
56
+ def get_cols(*args)
57
+ re = {}
58
+ args.flatten.map{|a| re[a] = @columns[a.to_sym]}
59
+ re
60
+ end
61
+
62
+ def runs(opts=nil)
63
+ init if @table.nil?
64
+ return App[@table] if opts.nil?
65
+ App[@table] = opts
66
+ end
67
+
68
+ def run(x, act, meth, *args)
69
+ App[@table][act.to_sym][meth.to_sym][x, *args]
70
+ end
71
+
72
+ def render(x, meth, *args)
73
+ const_get(x.ext.capitalize).send(meth, x, *args)
74
+ end
75
+
76
+ def parse_select(select, view)
77
+ raise "Can not define both select and view in Waxx::Object.parse_select (#{name})." if select and view
78
+ return select || "*" if view.nil?
79
+ view.columns.map{|n,c|
80
+ raise "Column #{n} not defined in #{view}" if c.nil?
81
+ if c[:sql_select]
82
+ "#{c[:sql_select]} AS #{n}"
83
+ elsif n != c[:column]
84
+ "#{c[:table]}.#{c[:column]} AS #{n}"
85
+ else
86
+ "#{c[:table]}.#{c[:column]}"
87
+ end
88
+ }.join(", ")
89
+ end
90
+
91
+ def get(x, select:nil, id:nil, joins:nil, where:nil, having:nil, order:nil, limit:nil, offset:nil, view:nil, &blk)
92
+ Waxx.debug "object.get"
93
+ select = parse_select(select, view)
94
+ where = ["#{@table}.#{@pkey} = $1",id] if id and where.nil?
95
+ # Block SQL injection in order clause. All order options must be defined in @orders.
96
+ if order
97
+ if not @orders/order
98
+ Waxx.debug("ERROR: Object.get order (#{order}) not found in @orders [#{@orders.keys.join(", ")}]. Sorting by #{@pkey} instead.")
99
+ order = @pkey
100
+ else
101
+ order = @orders/order
102
+ end
103
+ end
104
+ if joins.nil? and view
105
+ joins = view.joins_to_sql
106
+ end
107
+ q = {select:select, joins:joins, where:where, having:having, order:order, limit:limit, offset:offset}
108
+ yield q if block_given?
109
+ Waxx.debug "object.get.select: #{q[:select]}"
110
+ return [] if q[:select].empty?
111
+ sql = []
112
+ sql << "SELECT #{q[:select] || "*"}"
113
+ sql << "FROM #{@table} #{q[:joins]}"
114
+ sql << "WHERE #{q[:where][0]}" if q[:where]
115
+ sql << "HAVING #{q[:having[0]]}" if q[:having]
116
+ sql << "ORDER BY #{q[:order]}" if q[:order]
117
+ sql << "LIMIT #{q[:limit].to_i}" if q[:limit]
118
+ sql << "OFFSET #{q[:offset].to_i}" if q[:offset]
119
+ vals = []
120
+ vals << q[:where][1] if q[:where] and q[:where][1]
121
+ vals << q[:having][1] if q[:having] and q[:having][1]
122
+ #[sql.join(" "), vals.flatten]
123
+ Waxx.debug sql
124
+ Waxx.debug vals.join(", ")
125
+ x.db[@db].exec(sql.join(" "), vals.flatten)
126
+ end
127
+
128
+ def get_by_id(x, id, select=nil, view:nil)
129
+ get(x, id: id, select: select, view: view).first
130
+ end
131
+ alias by_id get_by_id
132
+
133
+ def post(x, data, cols:nil, returning:nil, view:nil, &blk)
134
+ if view
135
+ cols = view.columns.select{|n,c| c[:table] == @table}
136
+ else
137
+ cols ||= @columns
138
+ end
139
+ data = blk.call if block_given?
140
+ sql = "INSERT INTO #{@table} ("
141
+ names = []
142
+ vars = []
143
+ vals = []
144
+ ret = []
145
+ i = 1
146
+ cols.each{|n,v|
147
+ if data/n
148
+ names << n.to_s
149
+ vars << "$#{i}"
150
+ vals << cast(v, data/n)
151
+ i += 1
152
+ end
153
+ ret << n.to_s
154
+ }
155
+ sql << names.join(",")
156
+ sql << ") VALUES (#{vars.join(",")})"
157
+ sql << " RETURNING #{returning || ret.join(",")}"
158
+ Waxx.debug(sql)
159
+ Waxx.debug(vals)
160
+ x.db[@db].exec(sql, vals).first
161
+ end
162
+
163
+ def put(x, id, data, cols:nil, returning:nil, view:nil, where:nil, &blk)
164
+ if view
165
+ cols = view.columns.select{|n,c| c[:table] == @table}
166
+ else
167
+ cols ||= @columns
168
+ end
169
+ data = blk.call if block_given?
170
+ sql = "UPDATE #{@table} SET "
171
+ set = []
172
+ vals = []
173
+ ret = []
174
+ i = 1
175
+ Waxx.debug "data: #{data}"
176
+ cols.each{|n,v|
177
+ Waxx.debug "col: #{n}: #{v.inspect}"
178
+ if data.has_key? n.to_s or data.has_key? n.to_sym
179
+ set << "#{n} = $#{i}"
180
+ vals << cast(v, data/n)
181
+ ret << n.to_s
182
+ i += 1
183
+ end
184
+ }
185
+ sql << set.join(",")
186
+ sql << " WHERE #{@pkey} = $#{i} #{where} RETURNING #{returning || ret.join(",")}"
187
+ vals << id
188
+ Waxx.debug(sql)
189
+ Waxx.debug(vals)
190
+ x.db[@db].exec(sql, vals).first
191
+ end
192
+ alias patch put
193
+
194
+ def put_post(x, id, data, cols:nil, returning:nil, view: nil)
195
+ q = nil
196
+ q = get_by_id(x, id, @pkey) if id.to_i > 0
197
+ return post(x, data, cols: cols, returning: returning, view: view) if q.nil?
198
+ put(x, id, data, cols: cols, returning: returning, view: view)
199
+ end
200
+
201
+ def cast(col, val)
202
+ case col[:type].to_sym
203
+ when :int
204
+ val.to_s.empty? ? nil : val.to_i
205
+ when :float, :numeric
206
+ val.to_s.empty? ? nil : val.to_f
207
+ else
208
+ val
209
+ end
210
+ end
211
+
212
+ def delete(x, id)
213
+ x.db[@db].exec("DELETE FROM #{@table} WHERE #{@pkey} = $1", [id])
214
+ end
215
+
216
+ def order(req_order, default_order='')
217
+ return default_order if req_order.nil?
218
+ return orders[req_order.to_sym] if orders.has_key? req_order.to_sym
219
+ @pkey
220
+ end
221
+ end
@@ -0,0 +1,234 @@
1
+ # Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
2
+ # Released under the Apache Version 2 License. See LICENSE.txt.
3
+
4
+ ##
5
+ # The MySQL Object methods
6
+ module Waxx::Mysql2
7
+ extend self
8
+
9
+ attr :app
10
+ attr :db
11
+ attr :table
12
+ attr :columns
13
+ attr :pkey
14
+ attr :joins
15
+ attr :orders
16
+
17
+ ##
18
+ # Connect to a MySQL/MariaDB database
19
+ #
20
+ # Set in config.yaml:
21
+ # databases:
22
+ # app: mysql2://user:pass@host:port/database?opt1=val1;opt2=val2
23
+ def connect(conf={})
24
+ Mysql2::Client.new( conf )
25
+ end
26
+
27
+ def init(app:nil, db:"app", table:nil, pk:"id", cols:nil)
28
+ @app ||= (app || App.table_from_class(name)).to_sym
29
+ @db ||= db.to_sym
30
+ @table ||= (table || App.table_from_class(name)).to_sym
31
+ @pkey ||= pk.to_sym
32
+ @columns ||= {}
33
+ @joins ||= {}
34
+ @orders ||= {}
35
+ has(cols) if cols
36
+ end
37
+
38
+ def has(opts=nil)
39
+ init if @table.nil?
40
+ return @columns if opts.nil?
41
+ @columns = opts
42
+ @columns.each{|n,v|
43
+ v[:table] = @table
44
+ v[:column] = n
45
+ v[:views] = []
46
+ v[:label] ||= Waxx::Util.label(n)
47
+ @orders[n] = v[:order] || n
48
+ @orders["_#{n}".to_sym] = v[:_order] || "#{n} DESC"
49
+ @pkey = n if v[:pkey]
50
+ if v[:is]
51
+ r, tc = v[:is].split(":")
52
+ t, c = tc.split(".")
53
+ @joins[r] = {join: "INNER", table: t, col: c}
54
+ end
55
+ if v[:has]
56
+ r, tc = v[:has].split(":")
57
+ t, c = tc.split(".")
58
+ @joins[r] = {join: "LEFT", table: t, col: c}
59
+ end
60
+ }
61
+ end
62
+
63
+ def [](n)
64
+ @columns[n.to_sym]
65
+ end
66
+
67
+ def /(n)
68
+ @columns[n.to_sym]
69
+ end
70
+
71
+ def get_cols(*args)
72
+ re = {}
73
+ args.flatten.map{|a| re[a] = @columns[a.to_sym]}
74
+ re
75
+ end
76
+
77
+ def runs(opts=nil)
78
+ init if @app.nil?
79
+ return App[@app] if opts.nil?
80
+ App[@app] = opts
81
+ end
82
+
83
+ def run(x, act, meth, *args)
84
+ App[@app][act.to_sym][meth.to_sym][x, *args]
85
+ end
86
+
87
+ def parse_select(select, view)
88
+ raise "Can not define both select and view in Waxx::Object.parse_select (#{name})." if select and view
89
+ return select || "*" if view.nil?
90
+ view.columns.map{|n,c|
91
+ raise "Column #{n} not defined in #{view}" if c.nil?
92
+ if c[:sql_select]
93
+ "#{c[:sql_select]} AS #{n}"
94
+ elsif n != c[:column]
95
+ "#{c[:table]}.#{c[:column]} AS #{n}"
96
+ else
97
+ "#{c[:table]}.#{c[:column]}"
98
+ end
99
+ }.join(", ")
100
+ end
101
+
102
+ def get(x, select:nil, id:nil, joins:nil, where:nil, having:nil, order:nil, limit:nil, offset:nil, view:nil, &blk)
103
+ Waxx.debug "object.get"
104
+ select = parse_select(select, view)
105
+ where = ["#{@table}.#{@pkey} = ?",id] if id and where.nil?
106
+ # Block SQL injection in order clause. All order options must be defined in @orders.
107
+ if order
108
+ if not @orders/order
109
+ Waxx.debug("ERROR: Object.get order (#{order}) not found in @orders [#{@orders.keys.join(", ")}]. Sorting by #{@pkey} instead.")
110
+ order = @pkey
111
+ else
112
+ order = @orders/order
113
+ end
114
+ end
115
+ if joins.nil? and view
116
+ joins = view.joins_to_sql
117
+ end
118
+ q = {select:select, joins:joins, where:where, having:having, order:order, limit:limit, offset:offset}
119
+ yield q if block_given?
120
+ Waxx.debug "object.get.select: #{q[:select]}"
121
+ return [] if q[:select].empty?
122
+ sql = []
123
+ sql << "SELECT #{q[:select] || "*"}"
124
+ sql << "FROM #{@table} #{q[:joins]}"
125
+ sql << "WHERE #{q[:where][0]}" if q[:where]
126
+ sql << "HAVING #{q[:having[0]]}" if q[:having]
127
+ sql << "ORDER BY #{q[:order]}" if q[:order]
128
+ sql << "LIMIT #{q[:limit].to_i}" if q[:limit]
129
+ sql << "OFFSET #{q[:offset].to_i}" if q[:offset]
130
+ vals = []
131
+ vals << q[:where][1] if q[:where] and q[:where][1]
132
+ vals << q[:having][1] if q[:having] and q[:having][1]
133
+ #[sql.join(" "), vals.flatten]
134
+ Waxx.debug sql
135
+ Waxx.debug vals.join(", ")
136
+ x.db[@db].prepare(sql.join(" ")).execute(*(vals.flatten))
137
+ end
138
+
139
+ def get_by_id(x, id, select=nil, view:nil)
140
+ get(x, id: id, select: select, view: view).first
141
+ end
142
+ alias by_id get_by_id
143
+
144
+ def post(x, data, cols:nil, returning:nil, view:nil, &blk)
145
+ if view
146
+ cols = view.columns.select{|n,c| c[:table] == @table}
147
+ else
148
+ cols ||= @columns
149
+ end
150
+ data = blk.call if block_given?
151
+ sql = "INSERT INTO #{@table} ("
152
+ names = []
153
+ vars = []
154
+ vals = []
155
+ ret = []
156
+ i = 1
157
+ cols.each{|n,v|
158
+ if data/n
159
+ names << n.to_s
160
+ vars << "?"
161
+ vals << cast(v, data/n)
162
+ i += 1
163
+ end
164
+ ret << n.to_s
165
+ }
166
+ sql << names.join(",")
167
+ sql << ") VALUES (#{vars.join(",")})"
168
+ Waxx.debug(sql)
169
+ Waxx.debug(vals)
170
+ x.db[@db].prepare(sql).execute(*vals)
171
+ id = x.db[@db].last_id
172
+ x.db[@db].prepare("SELECT #{returning || ret.join(",")} FROM #{@table} WHERE #{@pkey} = ?").execute(id).first
173
+ end
174
+
175
+ def put(x, id, data, cols:nil, returning:nil, view:nil, where:nil, &blk)
176
+ if view
177
+ cols = view.columns.select{|n,c| c[:table] == @table}
178
+ else
179
+ cols ||= @columns
180
+ end
181
+ data = blk.call if block_given?
182
+ sql = "UPDATE #{@table} SET "
183
+ set = []
184
+ vals = []
185
+ ret = []
186
+ i = 1
187
+ Waxx.debug "data: #{data}"
188
+ cols.each{|n,v|
189
+ Waxx.debug "col: #{n}: #{v.inspect}"
190
+ if data.has_key? n.to_s or data.has_key? n.to_sym
191
+ set << "#{n} = ?"
192
+ vals << cast(v, data/n)
193
+ ret << n.to_s
194
+ i += 1
195
+ end
196
+ }
197
+ sql << set.join(",")
198
+ sql << " WHERE #{@pkey} = ? #{where}"
199
+ vals << id
200
+ Waxx.debug(sql)
201
+ Waxx.debug(vals)
202
+ x.db[@db].prepare(sql).execute(*vals)
203
+ x.db[@db].prepare("SELECT #{returning || ret.join(",")} FROM #{@table} WHERE #{@pkey} = ?").execute(id).first
204
+ end
205
+ alias patch put
206
+
207
+ def put_post(x, id, data, cols:nil, returning:nil, view: nil)
208
+ q = nil
209
+ q = get_by_id(x, id, @pkey) if id.to_i > 0
210
+ return post(x, data, cols: cols, returning: returning, view: view) if q.nil?
211
+ put(x, id, data, cols: cols, returning: returning, view: view)
212
+ end
213
+
214
+ def cast(col, val)
215
+ case col[:type].to_sym
216
+ when :int
217
+ val.to_s.empty? ? nil : val.to_i
218
+ when :float, :numeric
219
+ val.to_s.empty? ? nil : val.to_f
220
+ else
221
+ val
222
+ end
223
+ end
224
+
225
+ def delete(x, id)
226
+ x.db[@db].query("DELETE FROM #{@table} WHERE #{@pkey} = $1", [id])
227
+ end
228
+
229
+ def order(req_order, default_order='')
230
+ return default_order if req_order.nil?
231
+ return orders[req_order.to_sym] if orders.has_key? req_order.to_sym
232
+ @pkey
233
+ end
234
+ end
@@ -0,0 +1,115 @@
1
+ # Waxx Copyright (c) 2016 ePark labs Inc. & Daniel J. Fitzpatrick <dan@eparklabs.com> All rights reserved.
2
+ # Released under the Apache Version 2 License. See LICENSE.txt.
3
+
4
+ module Waxx::Object
5
+
6
+ attr :app
7
+
8
+ ##
9
+ # Define the app interface (routes), methods to run, and access control
10
+ #
11
+ # ```
12
+ # module App::Person
13
+ # extend Waxx::Object
14
+ #
15
+ # runs(
16
+ # default: 'list',
17
+ # list: {
18
+ # desc: "List people",
19
+ # acl: "user",
20
+ # get: -> (x) {
21
+ # x << x.db.app.exec("SELECT * FROM person ORDER BY last_name, first_name").map{|r| r}.to_json
22
+ # }
23
+ # }
24
+ # )
25
+ # end
26
+ # ```
27
+ #
28
+ # The special "default" key can be used to run a method when the act is not defined. In the example above, a request to `/person` will act like a request to `/person/list`
29
+ #
30
+ # Attributes of each argument to the runs method
31
+ #
32
+ # ```
33
+ # desc: A text description of the act. This is used in the documentation of your app
34
+ # acl: The access control list. See the ACL section below
35
+ # get: Handle GET requests
36
+ # put: Handle PUT requests
37
+ # post: Handle POST requests
38
+ # patch: Handle PATCH requests
39
+ # delete: Handle DELETE requests
40
+ # run: A generic handler for any request method (for example if you want all PUT, POST, PATCH, and DELETE requests to go to the same handler).
41
+ # ```
42
+ #
43
+ # ### ACL - Controlling access to your acts
44
+ #
45
+ # The ACL definition is very flexible. This means there are a lot of options.
46
+ #
47
+ # ```
48
+ # No acl parameter # The method is public
49
+ # acl: nil # The method is public
50
+ # acl: "*", "any", "public" # The method is public
51
+ # acl: "user" # Any logged-in user (anyone who logs in is in the group "user")
52
+ # acl: [:admin, :manager] # Anyone in the "admin" or "manager" group.
53
+ # acl: %w(admin manager) # Anyone in the "admin" or "manager" group.
54
+ # # A hash with request methods as keys. Includes the keys "read" for GET and HEAD and "write" for PUT, POST, PATCH, DELETE.
55
+ # acl: {
56
+ # get: "public", # Anyone can GET.
57
+ # write: "admin" # Only an admin can write
58
+ # }
59
+ # # A proc that return boolean (true = access granted, false = access denied)
60
+ # # The x variable is passed in.
61
+ # acl: -> (x) {
62
+ # x.req.env['X-Key'] == "Secret Key"
63
+ # }
64
+ # # Another example based on the client IP set by the proxy server
65
+ # acl: -> (x) {
66
+ # [x.req.env['X-Forwarded-For']].flatten.first == "10.20.40.80"
67
+ # }
68
+ # # Require a user to be in two groups
69
+ # acl: -> (x) {
70
+ # x.groups? :manager, :finance
71
+ # }
72
+ # ```
73
+ def runs(opts=nil)
74
+ @app ||= App.table_from_class(name).to_sym
75
+ return App[@app] if opts.nil?
76
+ App[@app] = opts
77
+ end
78
+
79
+ ##
80
+ # Run a act in the current app.
81
+ #
82
+ # ```
83
+ # module App::Person
84
+ # extend Waxx::Object
85
+ #
86
+ # runs(
87
+ # default: 'list',
88
+ # list: {
89
+ # desc: "List people (/person/list.json)",
90
+ # acl: "user",
91
+ # get: -> (x) {
92
+ # x << x.db.app.exec("SELECT * FROM person ORDER BY last_name, first_name").map{|r| r}.to_json
93
+ # }
94
+ # },
95
+ # everyone: {
96
+ # desc: "List everyone (/person/everyone.json)",
97
+ # acl: "user",
98
+ # get: -> (x) {
99
+ # # Run a different act in the same app
100
+ # run(x, :list, :get)
101
+ # }
102
+ # }
103
+ # )
104
+ # end
105
+ # ```
106
+ def run(x, act, meth, *args)
107
+ App[@app][act.to_sym][meth.to_sym][x, *args]
108
+ end
109
+
110
+ # Shortcut to Waxx.debug
111
+ def debug(str, level=3)
112
+ Waxx.debug(str, level)
113
+ end
114
+
115
+ end