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/patch.rb ADDED
@@ -0,0 +1,138 @@
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
+ # Patches to Ruby Classes
5
+ class Date
6
+ # HTML format for a date
7
+ def h
8
+ to_s.h
9
+ end
10
+ # Shortcut to format a date in strftime
11
+ def f(format='%d-%b-%Y')
12
+ strftime format
13
+ end
14
+ end
15
+ class FalseClass
16
+ # HTML format "false"
17
+ def h
18
+ "false"
19
+ end
20
+ # Format to a selected format (see TrueClass also)
21
+ # Format Options:
22
+ # yn: No
23
+ # tf: False
24
+ # icon: glyphicon (Bootstrap)
25
+ # num: 0
26
+ def f(format=:yn)
27
+ case format.to_sym
28
+ when :yn
29
+ "No"
30
+ when :tf
31
+ "False"
32
+ when :icon
33
+ '<span class="glyphicon glyphicon-minus" aria-hidden="true"></span>'
34
+ when :num
35
+ "0"
36
+ else
37
+ raise "Unknown format in FalseClass.f: #{format}. Needs to be :yn, :tf, :icon, or :num."
38
+ end
39
+ end
40
+ # Show false as zero
41
+ def to_i
42
+ 0
43
+ end
44
+ end
45
+ class Hash
46
+ # Add an symbol/string indifferent access to a hash
47
+ def /(k)
48
+ self[k.to_sym] || self[k.to_s]
49
+ end
50
+ end
51
+ class NilClass
52
+ # HTML format
53
+ def h
54
+ ""
55
+ end
56
+ # Format nil as and empty string (2nd param)
57
+ # This is mostly for nil values out of the database
58
+ # that have a format f() called on them.
59
+ def f(size=2, zero_as="", t=",", d=".")
60
+ zero_as
61
+ end
62
+
63
+ # Convert a nil to an empty symbol
64
+ def to_sym
65
+ "".to_sym
66
+ end
67
+ end
68
+ class Numeric
69
+ # HTML format (self -- no escaping needed)
70
+ def h
71
+ self
72
+ end
73
+ # Format a number
74
+ # size: number of decimal places
75
+ # zero_as: will display zero as "" (blank), "-" (dash), etc.
76
+ # t: thousands seperator
77
+ # d: decimal seperator
78
+ def f(size=2, zero_as="", t=",", d=".")
79
+ return zero_as if zero?
80
+ num_parts = to_s.split(".")
81
+ x = num_parts[0].gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{t}")
82
+ return x if size == 0
83
+ x << (d + (num_parts[1].to_s + "0000000")[0,size])
84
+ end
85
+ end
86
+ class String
87
+ # Escape HTML entities
88
+ def h
89
+ gsub(/[&\"<>]/, {'&'=>'&amp;', '"'=>'&quot;', '<'=>'&lt;', '>'=>'&gt;'})
90
+ end
91
+ # Convert a string to a number and format
92
+ # See Numeric.f()
93
+ def f(size=2, zero_as="", t=",", d=".")
94
+ return zero_as if to_f.zero?
95
+ num_parts = split(".")
96
+ x = num_parts[0].gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{t}")
97
+ return x if size == 0
98
+ x << (d + (num_parts[1].to_s + "0000000")[0,size])
99
+ end
100
+ end
101
+ class Time
102
+ # HTML format
103
+ def h
104
+ to_s.h
105
+ end
106
+ # Format time in strftime
107
+ def f(format='%d-%b-%Y')
108
+ strftime format
109
+ end
110
+ end
111
+ class TrueClass
112
+ def h
113
+ "true"
114
+ end
115
+ # Format to a selected format (see FalseClass also)
116
+ # Format Options:
117
+ # yn: Yes
118
+ # tf: True
119
+ # icon: glyphicon (Bootstrap)
120
+ # num: 1
121
+ def f(format=:yn)
122
+ case format.to_sym
123
+ when :text
124
+ "True"
125
+ when :icon
126
+ '<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>'
127
+ when :num
128
+ "1"
129
+ else
130
+ raise "Unknown format in TrueClass.f: #{format}. Needs to be :yn, :tf, :icon, or :num."
131
+ end
132
+ end
133
+
134
+ # Show true as 1
135
+ def to_i
136
+ 1
137
+ end
138
+ end
data/lib/waxx/pdf.rb ADDED
@@ -0,0 +1,69 @@
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
+ # require 'prawn' to use PDFs
5
+
6
+ module Waxx::Pdf
7
+
8
+ def new_doc(margin:50, orientation: "portrait", info: {})
9
+ Prawn::Document.new(:margin=>margin, :orientation=>orientation, :info=>info)
10
+ end
11
+
12
+ def doc_info(
13
+ x,
14
+ title: "Untitled",
15
+ author: nil,
16
+ subject: "",
17
+ keywords: "",
18
+ creator: "WAXX waxx.io",
19
+ producer: "Prawn",
20
+ creation_date: Time.new
21
+ )
22
+ {
23
+ :Title => title,
24
+ :Author => author || "#{x.usr['un']}",
25
+ :Subject => subject,
26
+ :Keywords => keywords,
27
+ :Creator => creator,
28
+ :Producer => producer,
29
+ :CreationDate => creation_date
30
+ }
31
+ end
32
+
33
+ def file_path(x)
34
+ "#{Waxx::Root}/tmp/#{Time.new.strftime('%Y%m%dT%H%M%S')}-u#{x.usr['id']}.pdf"
35
+ end
36
+
37
+ def get
38
+ pdf = new_doc
39
+ pdf.text "Hello from WAXX. You need to implement the get method in your layout. Then call render_file & return_file"
40
+ render_file(x, pdf)
41
+ return_file(x)
42
+ end
43
+
44
+ def render_file(x, pdf)
45
+ pdf.render_file file_path(x)
46
+ end
47
+
48
+ def return_file(x)
49
+ File.open(file_path(x), "rb"){|f| x << f.read}
50
+ end
51
+
52
+ def show_grid(pdf)
53
+ existing_color = pdf.stroke_color?
54
+ pdf.stroke_color Color::RGB.new(230, 230, 255)
55
+ (0..800).step(10){|a|
56
+ pdf.stroke_color Color::RGB.new(130, 130, 255) if (a % 100).zero?
57
+ pdf.line(a,0,a,620).stroke
58
+ pdf.stroke_color Color::RGB.new(230, 230, 255) if (a % 100).zero?
59
+ }
60
+
61
+ (0..620).step(10){|b|
62
+ pdf.stroke_color Color::RGB.new(130, 130, 255) if (b % 100).zero?
63
+ pdf.line(0,b,800,b).stroke
64
+ pdf.stroke_color Color::RGB.new(230, 230, 255) if (b % 100).zero?
65
+ }
66
+ pdf.stroke_color existing_color
67
+ end
68
+
69
+ end
data/lib/waxx/pg.rb ADDED
@@ -0,0 +1,246 @@
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 PostgreSQL Object methods
6
+ module Waxx::Pg
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 postgresql database
19
+ #
20
+ # Set in config.yaml:
21
+ # databases:
22
+ # app: postgresql://user:pass@host:port/database
23
+ def connect(str)
24
+ conn = PG.connect( str )
25
+ conn.type_map_for_results = PG::BasicTypeMapForResults.new conn
26
+ conn.type_map_for_queries = PG::BasicTypeMapForQueries.new conn
27
+ conn
28
+ end
29
+
30
+ def init(app:nil, db:"app", table:nil, pk:"id", cols:nil)
31
+ @app ||= (app || App.table_from_class(name)).to_sym
32
+ @db ||= db.to_sym
33
+ @table ||= (table || App.table_from_class(name)).to_sym
34
+ @pkey ||= pk.to_sym
35
+ @columns ||= {}
36
+ @joins ||= {}
37
+ @orders ||= {}
38
+ has(cols) if cols
39
+ end
40
+
41
+ def has(opts=nil)
42
+ init if @table.nil?
43
+ return @columns if opts.nil?
44
+ @columns = opts
45
+ @columns.each{|n,v|
46
+ v[:table] = @table
47
+ v[:column] = n
48
+ v[:views] = []
49
+ v[:label] ||= Waxx::Util.label(n)
50
+ @orders[n] = v[:order] || n
51
+ @orders["_#{n}".to_sym] = v[:_order] || "#{n} DESC"
52
+ @pkey = n if v[:pkey]
53
+ build_joins(n, v[:is])
54
+ }
55
+ end
56
+
57
+ def build_joins(n, col_is)
58
+ return if col_is.nil?
59
+ [col_is].flatten.each{|str|
60
+ r, tc = str.split(":")
61
+ t, c = tc.split(".")
62
+ j = c =~ /\+$/ ? "LEFT" : "INNER"
63
+ @joins[r] = {table: @table, col: n.to_s.strip, join: j.to_s.strip, foreign_table: t.to_s.strip, foreign_col: c.to_s.strip.sub('+','')}
64
+ }
65
+ end
66
+
67
+ def [](n)
68
+ @columns[n.to_sym]
69
+ end
70
+
71
+ def /(n)
72
+ @columns[n.to_sym]
73
+ end
74
+
75
+ def get_cols(*args)
76
+ re = {}
77
+ args.flatten.map{|a| re[a] = @columns[a.to_sym]}
78
+ re
79
+ end
80
+
81
+ def runs(opts=nil)
82
+ init if @app.nil?
83
+ return App[@app] if opts.nil?
84
+ App[@app] = opts
85
+ end
86
+
87
+ def run(x, act, meth, *args)
88
+ App[@app][act.to_sym][meth.to_sym][x, *args]
89
+ end
90
+
91
+ def parse_select(select, view)
92
+ raise "Can not define both select and view in Waxx::Object.parse_select (#{name})." if select and view
93
+ return select || "*" if view.nil?
94
+ view.columns.map{|n,c|
95
+ raise "Column #{n} not defined in #{view}" if c.nil?
96
+ if c[:sql_select]
97
+ "#{c[:sql_select]} AS #{n}"
98
+ elsif n != c[:column]
99
+ "#{c[:table]}.#{c[:column]} AS #{n}"
100
+ else
101
+ "#{c[:table]}.#{c[:column]}"
102
+ end
103
+ }.join(", ")
104
+ end
105
+
106
+ def get(x, select:nil, id:nil, joins:nil, where:nil, having:nil, order:nil, limit:nil, offset:nil, view:nil, &blk)
107
+ Waxx.debug "object.get"
108
+ select = parse_select(select, view)
109
+ where = ["#{@table}.#{@pkey} = $1",id] if id and where.nil?
110
+ # Block SQL injection in order clause. All order options must be defined in @orders.
111
+ if order
112
+ # Look in self orders
113
+ if not @orders/order
114
+ # Look in the view's columns
115
+ if view and view.orders/order
116
+ order = view.orders/order
117
+ else
118
+ Waxx.debug("ERROR: Object.get order (#{order}) not found in @orders [#{@orders.keys.join(", ")}]. Sorting by #{@pkey} instead.")
119
+ order = @pkey
120
+ end
121
+ else
122
+ order = @orders/order
123
+ end
124
+ end
125
+ if joins.nil? and view
126
+ joins = view.joins_to_sql
127
+ end
128
+ q = {select:select, joins:joins, where:where, having:having, order:order, limit:limit, offset:offset}
129
+ yield q if block_given?
130
+ Waxx.debug "object.get.select: #{q[:select]}"
131
+ return [] if q[:select].empty?
132
+ sql = []
133
+ sql << "SELECT #{q[:select] || "*"}"
134
+ sql << "FROM #{@table} #{q[:joins]}"
135
+ sql << "WHERE #{q[:where][0]}" if q[:where]
136
+ sql << "HAVING #{q[:having[0]]}" if q[:having]
137
+ sql << "ORDER BY #{q[:order]}" if q[:order]
138
+ sql << "LIMIT #{q[:limit].to_i}" if q[:limit]
139
+ sql << "OFFSET #{q[:offset].to_i}" if q[:offset]
140
+ vals = []
141
+ vals << q[:where][1] if q[:where] and q[:where][1]
142
+ vals << q[:having][1] if q[:having] and q[:having][1]
143
+ #[sql.join(" "), vals.flatten]
144
+ Waxx.debug sql
145
+ Waxx.debug vals.join(", ")
146
+ x.db[@db].exec(sql.join(" "), vals.flatten)
147
+ end
148
+
149
+ def get_by_id(x, id, select=nil, view:nil)
150
+ get(x, id: id, select: select, view: view).first
151
+ end
152
+ alias by_id get_by_id
153
+
154
+ def post(x, data, cols:nil, returning:nil, view:nil, &blk)
155
+ if view
156
+ cols = view.columns.select{|n,c| c[:table] == @table}
157
+ else
158
+ cols ||= @columns
159
+ end
160
+ data = blk.call if block_given?
161
+ sql = "INSERT INTO #{@table} ("
162
+ names = []
163
+ vars = []
164
+ vals = []
165
+ ret = []
166
+ i = 1
167
+ cols.each{|n,v|
168
+ if data/n
169
+ names << n.to_s
170
+ vars << "$#{i}"
171
+ vals << cast(v, data/n)
172
+ i += 1
173
+ end
174
+ ret << n.to_s
175
+ }
176
+ sql << names.join(",")
177
+ sql << ") VALUES (#{vars.join(",")})"
178
+ sql << " RETURNING #{returning || ret.join(",")}"
179
+ Waxx.debug(sql)
180
+ Waxx.debug(vals)
181
+ x.db[@db].exec(sql, vals).first
182
+ end
183
+
184
+ def put(x, id, data, cols:nil, returning:nil, view:nil, where:nil, &blk)
185
+ if view
186
+ cols = view.columns.select{|n,c| c[:table] == @table}
187
+ else
188
+ cols ||= @columns
189
+ end
190
+ data = blk.call if block_given?
191
+ sql = "UPDATE #{@table} SET "
192
+ set = []
193
+ vals = []
194
+ ret = []
195
+ i = 1
196
+ Waxx.debug "data: #{data}"
197
+ cols.each{|n,v|
198
+ Waxx.debug "col: #{n}: #{v.inspect}"
199
+ if data.has_key? n.to_s or data.has_key? n.to_sym
200
+ set << "#{n} = $#{i}"
201
+ vals << cast(v, data/n)
202
+ ret << n.to_s
203
+ i += 1
204
+ end
205
+ }
206
+ sql << set.join(",")
207
+ sql << " WHERE #{@pkey} = $#{i} #{where} RETURNING #{returning || ret.join(",")}"
208
+ vals << id
209
+ Waxx.debug(sql)
210
+ Waxx.debug(vals)
211
+ x.db[@db].exec(sql, vals).first
212
+ end
213
+ alias patch put
214
+
215
+ def put_post(x, id, data, cols:nil, returning:nil, view: nil)
216
+ q = nil
217
+ q = get_by_id(x, id, @pkey) if id.to_i > 0
218
+ return post(x, data, cols: cols, returning: returning, view: view) if q.nil?
219
+ put(x, id, data, cols: cols, returning: returning, view: view)
220
+ end
221
+
222
+ def cast(col, val)
223
+ case col[:type].to_sym
224
+ when :int
225
+ val.to_s.empty? ? nil : val.to_i
226
+ when :float, :numeric
227
+ val.to_s.empty? ? nil : val.to_f
228
+ else
229
+ val
230
+ end
231
+ end
232
+
233
+ def delete(x, id)
234
+ x.db[@db].exec("DELETE FROM #{@table} WHERE #{@pkey} = $1", [id])
235
+ end
236
+
237
+ def order(req_order, default_order='')
238
+ return default_order if req_order.nil?
239
+ return orders[req_order.to_sym] if orders.has_key? req_order.to_sym
240
+ @pkey
241
+ end
242
+
243
+ def debug(str, level=3)
244
+ Waxx.debug(str, level)
245
+ end
246
+ end