waxx 0.1.4 → 0.2.0
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.
- checksums.yaml +4 -4
 - data/README.md +8 -8
 - data/bin/waxx +4 -2
 - data/lib/.yardoc/checksums +30 -0
 - data/lib/.yardoc/complete +0 -0
 - data/lib/.yardoc/object_types +0 -0
 - data/lib/.yardoc/objects/root.dat +0 -0
 - data/lib/.yardoc/proxy_types +0 -0
 - data/lib/waxx/app.rb +9 -5
 - data/lib/waxx/conf.rb +3 -3
 - data/lib/waxx/console.rb +13 -3
 - data/lib/waxx/database.rb +12 -8
 - data/lib/waxx/generate.rb +189 -0
 - data/lib/waxx/http.rb +77 -34
 - data/lib/waxx/init.rb +3 -2
 - data/lib/waxx/object.rb +2 -2
 - data/lib/waxx/patch.rb +7 -0
 - data/lib/waxx/pdf.rb +2 -2
 - data/lib/waxx/pg.rb +73 -12
 - data/lib/waxx/res.rb +32 -8
 - data/lib/waxx/server.rb +5 -4
 - data/lib/waxx/version.rb +1 -1
 - data/lib/waxx/view.rb +41 -8
 - data/lib/waxx/waxx.rb +4 -4
 - data/lib/waxx/x.rb +14 -2
 - data/lib/waxx.rb +1 -1
 - data/skel/app/about/about.rb +32 -0
 - data/skel/app/home/html.rb +5 -135
 - data/skel/app/html.rb +38 -124
 - data/skel/app/usr/usr.rb +4 -4
 - data/skel/app/waxx/waxx.rb +1 -1
 - data/skel/public/lib/waxx/waxx.js +0 -1
 - metadata +14 -36
 - checksums.yaml.gz.sig +0 -0
 - data/skel/public/lib/site.css +0 -202
 - data.tar.gz.sig +0 -4
 - metadata.gz.sig +0 -0
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: d48f18168120d265fbad00f5c097e897fc2100475c2fc5c16ca2e0ac0fdd065a
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 49cb992829fadcf39605e9052db7ff1d0ec10b06b0a76c1f84d7f9d6b5f85c5e
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 84f8791ac7b156387e1a4780ad3bf05e5f5ddb7ee1d4735f47ddd75c714452a1ccb0f0994becd324a80ded687b080e2ed01bf6d17eaf21de6ec39f97ae9cf00a
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 1163ef8ad6da886481ea0df6d02c32357ef49c380105f487e320a33822ac4e9f460b0a801707e386f5d127f15a560819c270f5047f96c04a8206bd2a3cb966d3
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -80,11 +80,11 @@ You specify the number of threads in the config file. 
     | 
|
| 
       80 
80 
     | 
    
         
             
            Each thread is prespawned and each thread makes it's own database connection.
         
     | 
| 
       81 
81 
     | 
    
         
             
            Requests are received and put into a FIFO request queue.
         
     | 
| 
       82 
82 
     | 
    
         
             
            The threads work through the queue.
         
     | 
| 
       83 
     | 
    
         
            -
            Each request, including session management, a database query, access control, and rendering in HTML or JSON is approximately 1 
     | 
| 
      
 83 
     | 
    
         
            +
            Each request, including session management, a database query, access control, and rendering in HTML or JSON is approximately 1 ms (on a modern laptop or server).
         
     | 
| 
       84 
84 
     | 
    
         
             
            With additional libraries, Waxx also easily generates XML, XLSX, CSV, PDF, etc.
         
     | 
| 
       85 
85 
     | 
    
         | 
| 
       86 
86 
     | 
    
         
             
            ### Easy to Grok
         
     | 
| 
       87 
     | 
    
         
            -
            Waxx has no  
     | 
| 
      
 87 
     | 
    
         
            +
            Waxx has no classes.
         
     | 
| 
       88 
88 
     | 
    
         
             
            It is Module-based and the Modules have methods (functions).
         
     | 
| 
       89 
89 
     | 
    
         
             
            Each method within a Module is given parameters and the method runs in isolation.
         
     | 
| 
       90 
90 
     | 
    
         
             
            There are no instance variables and no global variables.
         
     | 
| 
         @@ -92,7 +92,7 @@ Consequently, it is very easy to understand what any method does and it is very 
     | 
|
| 
       92 
92 
     | 
    
         
             
            You can call any method in the whole system from the console using `waxx console`.
         
     | 
| 
       93 
93 
     | 
    
         
             
            Passing in the same variables to a function will always return the same result.
         
     | 
| 
       94 
94 
     | 
    
         
             
            Waxx does have `x.res.out` variable, which is appended to with `x << "text"`, that is passed into each method and any method can append to the response body or set response headers.
         
     | 
| 
       95 
     | 
    
         
            -
            So it is not truly functional because this is  
     | 
| 
      
 95 
     | 
    
         
            +
            So it is not truly functional because this is a side effect.
         
     | 
| 
       96 
96 
     | 
    
         
             
            My opinion is that when you are building a response, then copying the response on every method is a waste of resources.
         
     | 
| 
       97 
97 
     | 
    
         
             
            So it does have this side effect by design.
         
     | 
| 
       98 
98 
     | 
    
         | 
| 
         @@ -112,11 +112,11 @@ So it does have this side effect by design. 
     | 
|
| 
       112 
112 
     | 
    
         
             
              - `x.req.get` is a hash of vars passed in the query string
         
     | 
| 
       113 
113 
     | 
    
         
             
              - `x.req.post` is a hash of vars passed in the body of the request
         
     | 
| 
       114 
114 
     | 
    
         
             
              - `x.req.env` is a hash of the environment
         
     | 
| 
       115 
     | 
    
         
            -
              - `x.req[' 
     | 
| 
      
 115 
     | 
    
         
            +
              - `x.req['header-name']` is a shortcut to incoming headers / environment vars - always lower-case
         
     | 
| 
       116 
116 
     | 
    
         
             
              - `x['param_name']` and `x/:param_name` are shortcuts to get and post vars (post vars override get vars)
         
     | 
| 
       117 
117 
     | 
    
         
             
            - `x.res` contains the status, response cookies, headers, and content body
         
     | 
| 
       118 
118 
     | 
    
         
             
              - `x << "some text"` appends to the body
         
     | 
| 
       119 
     | 
    
         
            -
              - `x.res[' 
     | 
| 
      
 119 
     | 
    
         
            +
              - `x.res['header-name'] = "value"` to set a response header
         
     | 
| 
       120 
120 
     | 
    
         
             
              - `x.status = 404` set the status. Defaults to 200.
         
     | 
| 
       121 
121 
     | 
    
         
             
            - `x.usr` is the session cookie hash (set expiration params in opt/{env}/config.yaml)
         
     | 
| 
       122 
122 
     | 
    
         
             
              - `x.usr['name'] = 'Joe'` will set the name variable in the `x.usr` variable accross requests.
         
     | 
| 
         @@ -130,10 +130,10 @@ See [Waxx Docs](https://www.waxx.io/doc/code) for more info. 
     | 
|
| 
       130 
130 
     | 
    
         
             
            1. HTTP request is received by Waxx (Use a reverse proxy/load balancer/https server like NGINX first for production)
         
     | 
| 
       131 
131 
     | 
    
         
             
            2. The request is placed in a queue: `Waxx::Server.queue`
         
     | 
| 
       132 
132 
     | 
    
         
             
            3. The request is popped off the queue by a Ruby green thread and parsed
         
     | 
| 
       133 
     | 
    
         
            -
            4. The variable `x` is created with the request `x.req` and response `x.res`.
         
     | 
| 
      
 133 
     | 
    
         
            +
            4. The variable `x` is created with the request `x.req` and response `x.res` and DB connections in `x.db`.
         
     | 
| 
       134 
134 
     | 
    
         
             
            5. The run method is called for the appropriate app (a namespaced RPC). All routes are: /app/act/[arg1/args2/arg3/...] => app is the module and act is the method to call with the args.
         
     | 
| 
       135 
     | 
    
         
            -
            6. You output to the response using `x << "output"` or using helper methods: `App::Html. 
     | 
| 
       136 
     | 
    
         
            -
            7. The response is returned to the client. Partial, chunked, and streamed responses are supported as well  
     | 
| 
      
 135 
     | 
    
         
            +
            6. You output to the response using `x << "output"` or using helper methods: `App::Html.render(...)`
         
     | 
| 
      
 136 
     | 
    
         
            +
            7. The response is returned to the client. Partial, chunked, and streamed responses are supported as well. You have direct access to the IO.
         
     | 
| 
       137 
137 
     | 
    
         | 
| 
       138 
138 
     | 
    
         
             
            ## Fast to Develop
         
     | 
| 
       139 
139 
     | 
    
         | 
    
        data/bin/waxx
    CHANGED
    
    | 
         @@ -3,7 +3,7 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            require 'optparse'
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            command = ARGV[0]    
         
     | 
| 
       6 
     | 
    
         
            -
            commands = %w(on off buff start stop restart console get put post delete patch config migrate migration deploy test init help)
         
     | 
| 
      
 6 
     | 
    
         
            +
            commands = %w(on off buff start stop restart console get put post delete patch config migrate migration deploy test init gen generate help)
         
     | 
| 
       7 
7 
     | 
    
         
             
            if not commands.include? command
         
     | 
| 
       8 
8 
     | 
    
         
             
              puts "Enter a command: #{commands.join(", ")}"
         
     | 
| 
       9 
9 
     | 
    
         
             
              puts "waxx --help for all options"
         
     | 
| 
         @@ -110,7 +110,9 @@ end 
     | 
|
| 
       110 
110 
     | 
    
         
             
            if Waxx::Console::Command.respond_to? command
         
     | 
| 
       111 
111 
     | 
    
         
             
              if %w(migration).include? command
         
     | 
| 
       112 
112 
     | 
    
         
             
                Waxx::Console::Command.send(command, ARGV[1], ARGV[2], opts)
         
     | 
| 
       113 
     | 
    
         
            -
              elsif %w( 
     | 
| 
      
 113 
     | 
    
         
            +
              elsif %w(gen generate).include? command
         
     | 
| 
      
 114 
     | 
    
         
            +
                Waxx::Console::Command.send(command, *ARGV.slice(1..))
         
     | 
| 
      
 115 
     | 
    
         
            +
              elsif %w(get post put delete patch test deploy migrate).include? command
         
     | 
| 
       114 
116 
     | 
    
         
             
                Waxx::Console::Command.send(command, ARGV[1], opts)
         
     | 
| 
       115 
117 
     | 
    
         
             
              else
         
     | 
| 
       116 
118 
     | 
    
         
             
                Waxx::Console::Command.send(command, opts)
         
     | 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            waxx/app.rb 44dff36d6d504ad141ef0db05796356117533858
         
     | 
| 
      
 2 
     | 
    
         
            +
            waxx/conf.rb ffecdb880e8a57bc1aeb1f6806cee120803fc3e3
         
     | 
| 
      
 3 
     | 
    
         
            +
            waxx/console.rb 6d2072ee1c426ade3d7f69aa1c7a7c34f56115d4
         
     | 
| 
      
 4 
     | 
    
         
            +
            waxx/csrf.rb 5ed5af0e892a25421bcb604b3bb527b3ecb4f016
         
     | 
| 
      
 5 
     | 
    
         
            +
            waxx/database.rb 65c27b3b5819498e400b9d76996bf4d0c814b42e
         
     | 
| 
      
 6 
     | 
    
         
            +
            waxx/encrypt.rb 13ba4c1eeedae72cc7b84cda96f93281f8bca51a
         
     | 
| 
      
 7 
     | 
    
         
            +
            waxx/error.rb 86e9fa4c33e381b88234393d01f88882e609a164
         
     | 
| 
      
 8 
     | 
    
         
            +
            waxx/html.rb 57cbca81c7e3175b090e1ec4159f3c5dd13624b8
         
     | 
| 
      
 9 
     | 
    
         
            +
            waxx/http.rb 7ead01576646c232dadba35858612d46aa2a1762
         
     | 
| 
      
 10 
     | 
    
         
            +
            waxx/init.rb ab6cff9000bb848f173d8bb9fd7a9ccc5337a678
         
     | 
| 
      
 11 
     | 
    
         
            +
            waxx/irb.rb 3a68cbfffefcbd7f9bc1377f3e6778aa62ea48d5
         
     | 
| 
      
 12 
     | 
    
         
            +
            waxx/irb_env.rb 403613b5b1b269df90ae02049c3584dfa9c253f8
         
     | 
| 
      
 13 
     | 
    
         
            +
            waxx/json.rb ca90d0f0f8179a6c30d58c69024af6316e2c9e1b
         
     | 
| 
      
 14 
     | 
    
         
            +
            waxx/mongodb.rb e08957a8d225418541265e6a278fa8667ce79b30
         
     | 
| 
      
 15 
     | 
    
         
            +
            waxx/mysql2.rb 0bd1d416d7a91cd1e20fc3d785907ee86e18eb69
         
     | 
| 
      
 16 
     | 
    
         
            +
            waxx/object.rb 2c2aa5f86fd66c24a0522a6734aa69a2285a3a58
         
     | 
| 
      
 17 
     | 
    
         
            +
            waxx/patch.rb 6795d921bf481dbe72269aa3f3d8156ef27c00cc
         
     | 
| 
      
 18 
     | 
    
         
            +
            waxx/pdf.rb eb7b7d5c06dd65930303dd003aee2c8ba28fab94
         
     | 
| 
      
 19 
     | 
    
         
            +
            waxx/pg.rb 74ed59fb57ce4e3a1adfdf43429d7be3bbd1725f
         
     | 
| 
      
 20 
     | 
    
         
            +
            waxx/process.rb a6d97846c5c2b55181a67e88a112e885b941eede
         
     | 
| 
      
 21 
     | 
    
         
            +
            waxx/req.rb 512961f28140e2f984943141d49ba6a1b3bb8368
         
     | 
| 
      
 22 
     | 
    
         
            +
            waxx/res.rb c35d377fe31e0af1de8f3edc833d4e90e6d88c7d
         
     | 
| 
      
 23 
     | 
    
         
            +
            waxx/server.rb 3142a3cf6d974c2f2ffe7bfa0e40b2899c4afd14
         
     | 
| 
      
 24 
     | 
    
         
            +
            waxx/sqlite3.rb f3a9a566ffbeb82625f8aaaf96f375c6b49cef75
         
     | 
| 
      
 25 
     | 
    
         
            +
            waxx/supervisor.rb dbe5fd12f2308c765b72f88e620a06deed7b06ba
         
     | 
| 
      
 26 
     | 
    
         
            +
            waxx/test.rb fd7b41fcca24e09fd58270c4fd56745d9d346f38
         
     | 
| 
      
 27 
     | 
    
         
            +
            waxx/util.rb aca719489717efb31e7c5d219a04f95457b30534
         
     | 
| 
      
 28 
     | 
    
         
            +
            waxx/view.rb 0a9d4e4d4154dea45217bc093801b98c3571be68
         
     | 
| 
      
 29 
     | 
    
         
            +
            waxx/waxx.rb 6df4053942c329088b71e6c33e63cc4012ee80fb
         
     | 
| 
      
 30 
     | 
    
         
            +
            waxx/x.rb 9309f97e707660bd91c840b7c43af3a17b0e2577
         
     | 
| 
         
            File without changes
         
     | 
| 
         Binary file 
     | 
| 
         Binary file 
     | 
| 
         Binary file 
     | 
    
        data/lib/waxx/app.rb
    CHANGED
    
    | 
         @@ -100,9 +100,13 @@ module Waxx::App 
     | 
|
| 
       100 
100 
     | 
    
         
             
              # Layouts in app/app/error/*
         
     | 
| 
       101 
101 
     | 
    
         
             
              def error(x, status:200, type:"request", title:"An error occurred", message:"", args: [])
         
     | 
| 
       102 
102 
     | 
    
         
             
                x.res.status = status
         
     | 
| 
       103 
     | 
    
         
            -
                 
     | 
| 
       104 
     | 
    
         
            -
                  App[:app_error][type.to_sym] 
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
      
 103 
     | 
    
         
            +
                begin
         
     | 
| 
      
 104 
     | 
    
         
            +
                  if App[:app_error][type.to_sym]
         
     | 
| 
      
 105 
     | 
    
         
            +
                    App[:app_error][type.to_sym][:get][x, title, message, *args]
         
     | 
| 
      
 106 
     | 
    
         
            +
                  else
         
     | 
| 
      
 107 
     | 
    
         
            +
                    x << "ERROR: #{title} - #{message}"
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
                rescue
         
     | 
| 
       106 
110 
     | 
    
         
             
                  x << "ERROR: #{title} - #{message}"
         
     | 
| 
       107 
111 
     | 
    
         
             
                end
         
     | 
| 
       108 
112 
     | 
    
         
             
              end
         
     | 
| 
         @@ -141,7 +145,7 @@ module Waxx::App 
     | 
|
| 
       141 
145 
     | 
    
         
             
                  end
         
     | 
| 
       142 
146 
     | 
    
         
             
                  return false if g.nil?
         
     | 
| 
       143 
147 
     | 
    
         
             
                  return true if %w(* all any public).include? g.to_s
         
     | 
| 
       144 
     | 
    
         
            -
                  return access?(x, g)
         
     | 
| 
      
 148 
     | 
    
         
            +
                  return access?(x, acl: g)
         
     | 
| 
       145 
149 
     | 
    
         
             
                when Proc
         
     | 
| 
       146 
150 
     | 
    
         
             
                  return acl.call(x)
         
     | 
| 
       147 
151 
     | 
    
         
             
                else
         
     | 
| 
         @@ -163,7 +167,7 @@ module Waxx::App 
     | 
|
| 
       163 
167 
     | 
    
         
             
              def login_needed(x)
         
     | 
| 
       164 
168 
     | 
    
         
             
                if x.ext == "json"
         
     | 
| 
       165 
169 
     | 
    
         
             
                  x.res.status = 400
         
     | 
| 
       166 
     | 
    
         
            -
                  x << {ok: false, msg: 'Login needed: Session did not pass ACL'}
         
     | 
| 
      
 170 
     | 
    
         
            +
                  x << {ok: false, msg: 'Login needed: Session did not pass ACL'}.to_json
         
     | 
| 
       167 
171 
     | 
    
         
             
                else
         
     | 
| 
       168 
172 
     | 
    
         
             
                  App::Html.render(x,
         
     | 
| 
       169 
173 
     | 
    
         
             
                    title: "Please Login",
         
     | 
    
        data/lib/waxx/conf.rb
    CHANGED
    
    | 
         @@ -35,19 +35,19 @@ module Waxx::Conf 
     | 
|
| 
       35 
35 
     | 
    
         
             
              ##
         
     | 
| 
       36 
36 
     | 
    
         
             
              # Get a Waxx variable
         
     | 
| 
       37 
37 
     | 
    
         
             
              def [](n)
         
     | 
| 
       38 
     | 
    
         
            -
                @data[n]
         
     | 
| 
      
 38 
     | 
    
         
            +
                @data[n.to_s]
         
     | 
| 
       39 
39 
     | 
    
         
             
              end
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
       41 
41 
     | 
    
         
             
              ##
         
     | 
| 
       42 
42 
     | 
    
         
             
              # Set a conf variable
         
     | 
| 
       43 
43 
     | 
    
         
             
              def []=(n, v)
         
     | 
| 
       44 
     | 
    
         
            -
                @data[n] = v
         
     | 
| 
      
 44 
     | 
    
         
            +
                @data[n.to_s] = v
         
     | 
| 
       45 
45 
     | 
    
         
             
              end
         
     | 
| 
       46 
46 
     | 
    
         | 
| 
       47 
47 
     | 
    
         
             
              ##
         
     | 
| 
       48 
48 
     | 
    
         
             
              # Get a Waxx variable
         
     | 
| 
       49 
49 
     | 
    
         
             
              def /(n)
         
     | 
| 
       50 
     | 
    
         
            -
                @data[n.to_s] 
     | 
| 
      
 50 
     | 
    
         
            +
                @data[n.to_s]
         
     | 
| 
       51 
51 
     | 
    
         
             
              end
         
     | 
| 
       52 
52 
     | 
    
         | 
| 
       53 
53 
     | 
    
         
             
            end
         
     | 
    
        data/lib/waxx/console.rb
    CHANGED
    
    | 
         @@ -103,7 +103,7 @@ module Waxx::Console 
     | 
|
| 
       103 
103 
     | 
    
         
             
                  App.put(ARGV[1], opts)
         
     | 
| 
       104 
104 
     | 
    
         
             
                end
         
     | 
| 
       105 
105 
     | 
    
         | 
| 
       106 
     | 
    
         
            -
                def  
     | 
| 
      
 106 
     | 
    
         
            +
                def del(opts)
         
     | 
| 
       107 
107 
     | 
    
         
             
                  App.delete(ARGV[1], opts)
         
     | 
| 
       108 
108 
     | 
    
         
             
                end
         
     | 
| 
       109 
109 
     | 
    
         | 
| 
         @@ -114,7 +114,7 @@ module Waxx::Console 
     | 
|
| 
       114 
114 
     | 
    
         
             
                    #help = "Use the source, Luke"
         
     | 
| 
       115 
115 
     | 
    
         
             
                    begin
         
     | 
| 
       116 
116 
     | 
    
         
             
                      x = Waxx::Console.x
         
     | 
| 
       117 
     | 
    
         
            -
                      binding.irb
         
     | 
| 
      
 117 
     | 
    
         
            +
                      binding.irb(show_code: false)
         
     | 
| 
       118 
118 
     | 
    
         
             
                    rescue
         
     | 
| 
       119 
119 
     | 
    
         
             
                      IRB.setup(nil)
         
     | 
| 
       120 
120 
     | 
    
         
             
                      workspace = IRB::WorkSpace.new(self)
         
     | 
| 
         @@ -175,7 +175,7 @@ module Waxx::Console 
     | 
|
| 
       175 
175 
     | 
    
         
             
                  if target == "waxx"
         
     | 
| 
       176 
176 
     | 
    
         
             
                    tests = []
         
     | 
| 
       177 
177 
     | 
    
         
             
                    Dir.entries(opts[:base] + '/test').each{|f|
         
     | 
| 
       178 
     | 
    
         
            -
                      next if f =~ /^\./
         
     | 
| 
      
 178 
     | 
    
         
            +
                      next if f =~ /^\./ or not f =~ /\.rb$/
         
     | 
| 
       179 
179 
     | 
    
         
             
                      tests << f.sub(/\.rb$/,"")
         
     | 
| 
       180 
180 
     | 
    
         
             
                      path = opts[:base] + '/test/' + f
         
     | 
| 
       181 
181 
     | 
    
         
             
                      puts path
         
     | 
| 
         @@ -203,6 +203,16 @@ module Waxx::Console 
     | 
|
| 
       203 
203 
     | 
    
         
             
                  puts re.send("to_#{opts[:format]}")
         
     | 
| 
       204 
204 
     | 
    
         
             
                end
         
     | 
| 
       205 
205 
     | 
    
         | 
| 
      
 206 
     | 
    
         
            +
                def generate(scope, app, act=nil, type='record')
         
     | 
| 
      
 207 
     | 
    
         
            +
                  unless File.exist? 'app/app.rb'
         
     | 
| 
      
 208 
     | 
    
         
            +
                    puts "Error: You need to call 'waxx generate' from the root of a waxx installation."
         
     | 
| 
      
 209 
     | 
    
         
            +
                    return
         
     | 
| 
      
 210 
     | 
    
         
            +
                  end
         
     | 
| 
      
 211 
     | 
    
         
            +
                  x = Waxx::Console.x
         
     | 
| 
      
 212 
     | 
    
         
            +
                  Waxx::Generate.gen(x, scope, app, act, type)
         
     | 
| 
      
 213 
     | 
    
         
            +
                end
         
     | 
| 
      
 214 
     | 
    
         
            +
                alias gen generate
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
       206 
216 
     | 
    
         
             
              end
         
     | 
| 
       207 
217 
     | 
    
         | 
| 
       208 
218 
     | 
    
         
             
            end
         
     | 
    
        data/lib/waxx/database.rb
    CHANGED
    
    | 
         @@ -65,14 +65,18 @@ module Waxx::Database 
     | 
|
| 
       65 
65 
     | 
    
         
             
                  next if db_only and db_only.to_sym != name
         
     | 
| 
       66 
66 
     | 
    
         
             
                  puts "Migrating: db.#{name}"
         
     | 
| 
       67 
67 
     | 
    
         
             
                  # get the latest version
         
     | 
| 
       68 
     | 
    
         
            -
                  latest = db.exec("SELECT value FROM waxx WHERE name = 'db 
     | 
| 
       69 
     | 
    
         
            -
                   
     | 
| 
       70 
     | 
    
         
            -
                     
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
                       
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
      
 68 
     | 
    
         
            +
                  latest = db.exec("SELECT value FROM waxx WHERE name = 'db.migration.last'").first['value'] rescue nil
         
     | 
| 
      
 69 
     | 
    
         
            +
                  if latest.nil?
         
     | 
| 
      
 70 
     | 
    
         
            +
                    puts "WARNING: No db.migration.last key in waxx table for #{name}"
         
     | 
| 
      
 71 
     | 
    
         
            +
                  else
         
     | 
| 
      
 72 
     | 
    
         
            +
                    Dir.entries("#{opts[:base]}/db/#{name}/").sort.each{|f|
         
     | 
| 
      
 73 
     | 
    
         
            +
                      if f =~ /\.sql$/ and f > latest
         
     | 
| 
      
 74 
     | 
    
         
            +
                        puts "  #{f}"
         
     | 
| 
      
 75 
     | 
    
         
            +
                        db.exec(File.read("#{opts[:base]}/db/#{name}/#{f}"))
         
     | 
| 
      
 76 
     | 
    
         
            +
                        db.exec("UPDATE waxx SET value = $1 WHERE name = 'db.migration.last'",[f])
         
     | 
| 
      
 77 
     | 
    
         
            +
                      end
         
     | 
| 
      
 78 
     | 
    
         
            +
                    }
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
       76 
80 
     | 
    
         
             
                }
         
     | 
| 
       77 
81 
     | 
    
         
             
                puts "Migration complete"
         
     | 
| 
       78 
82 
     | 
    
         
             
              end
         
     | 
| 
         @@ -0,0 +1,189 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Waxx::Generate
         
     | 
| 
      
 2 
     | 
    
         
            +
              extend self
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
              def gen(x, scope, app, act=nil, type='record')
         
     | 
| 
      
 5 
     | 
    
         
            +
                folder = app_folder(app)
         
     | 
| 
      
 6 
     | 
    
         
            +
                columns = Waxx::Pg.columns_for(x, app)
         
     | 
| 
      
 7 
     | 
    
         
            +
                if %w(app object obj).include? scope.to_s
         
     | 
| 
      
 8 
     | 
    
         
            +
                  obj(folder, app, columns)
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
                if %w(view).include? scope.to_s
         
     | 
| 
      
 11 
     | 
    
         
            +
                  view(folder, app, act, type, columns)
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
                if %w(app).include? scope.to_s
         
     | 
| 
      
 14 
     | 
    
         
            +
                  view(folder, app, 'list', 'list', columns)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  view(folder, app, 'record', 'record', columns)
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              def app_folder(app)
         
     | 
| 
      
 20 
     | 
    
         
            +
                folder = "app/#{app.to_s.strip.gsub("_","/")}"
         
     | 
| 
      
 21 
     | 
    
         
            +
                begin
         
     | 
| 
      
 22 
     | 
    
         
            +
                  FileUtils.mkdir_p folder
         
     | 
| 
      
 23 
     | 
    
         
            +
                  puts "Created folder #{folder}"
         
     | 
| 
      
 24 
     | 
    
         
            +
                rescue => e
         
     | 
| 
      
 25 
     | 
    
         
            +
                  puts "Could not make app folder. Skipping."
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
                folder
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              def obj(folder, app, columns)
         
     | 
| 
      
 31 
     | 
    
         
            +
                file = "#{folder}/#{app.strip}.rb"
         
     | 
| 
      
 32 
     | 
    
         
            +
                if File.exist? file
         
     | 
| 
      
 33 
     | 
    
         
            +
                  puts "#{file} already exists. Skipping."
         
     | 
| 
      
 34 
     | 
    
         
            +
                  return
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
                # Build the object file
         
     | 
| 
      
 37 
     | 
    
         
            +
                re = [
         
     | 
| 
      
 38 
     | 
    
         
            +
                  "module App::#{Waxx::Util.camel_case(app.strip)}",
         
     | 
| 
      
 39 
     | 
    
         
            +
                  "  extend Waxx::Pg",
         
     | 
| 
      
 40 
     | 
    
         
            +
                  "  extend self",
         
     | 
| 
      
 41 
     | 
    
         
            +
                  "",
         
     | 
| 
      
 42 
     | 
    
         
            +
                  "  has(",
         
     | 
| 
      
 43 
     | 
    
         
            +
                ]
         
     | 
| 
      
 44 
     | 
    
         
            +
                columns.each{|rec|
         
     | 
| 
      
 45 
     | 
    
         
            +
                  primary = rec['pkey'] ? ", pkey: true" : ""
         
     | 
| 
      
 46 
     | 
    
         
            +
                  re << %(    #{rec['column_name']}: {type: '#{rec['data_type'].split(' ').first  }'#{primary}},) 
         
     | 
| 
      
 47 
     | 
    
         
            +
                }
         
     | 
| 
      
 48 
     | 
    
         
            +
                re << [
         
     | 
| 
      
 49 
     | 
    
         
            +
                  "  )",
         
     | 
| 
      
 50 
     | 
    
         
            +
                  "",
         
     | 
| 
      
 51 
     | 
    
         
            +
                  "  runs(",
         
     | 
| 
      
 52 
     | 
    
         
            +
                  "    default: 'list',",
         
     | 
| 
      
 53 
     | 
    
         
            +
                  "    list: {",
         
     | 
| 
      
 54 
     | 
    
         
            +
                  "      desc: 'List #{app} records',",
         
     | 
| 
      
 55 
     | 
    
         
            +
                  "      acl: %w(user),",
         
     | 
| 
      
 56 
     | 
    
         
            +
                  "      get: -> (x) {",
         
     | 
| 
      
 57 
     | 
    
         
            +
                  "        #{app}s = List.get(x)",
         
     | 
| 
      
 58 
     | 
    
         
            +
                  "        List.render(x, #{app}s)",
         
     | 
| 
      
 59 
     | 
    
         
            +
                  "      }",
         
     | 
| 
      
 60 
     | 
    
         
            +
                  "    },",
         
     | 
| 
      
 61 
     | 
    
         
            +
                  "    record: {",
         
     | 
| 
      
 62 
     | 
    
         
            +
                  "      desc: 'CRUD #{app} records',",
         
     | 
| 
      
 63 
     | 
    
         
            +
                  "      acl: %w(user),",
         
     | 
| 
      
 64 
     | 
    
         
            +
                  "      get: -> (x, id=0) {",
         
     | 
| 
      
 65 
     | 
    
         
            +
                  "        #{app} = id.to_i == 0 ? {id: 0} : Record.by_id(x, id)",
         
     | 
| 
      
 66 
     | 
    
         
            +
                  "        Record.render(x, #{app})",
         
     | 
| 
      
 67 
     | 
    
         
            +
                  "      },",
         
     | 
| 
      
 68 
     | 
    
         
            +
                  "      post: -> (x, id=0) {",
         
     | 
| 
      
 69 
     | 
    
         
            +
                  "        #{app} = id.to_i == 0 ? Record.post(x, x.req.post) : Record.put(x, id, x.req.post)",
         
     | 
| 
      
 70 
     | 
    
         
            +
                  "        return x << #{app}.to_json if x.ext == 'json'",
         
     | 
| 
      
 71 
     | 
    
         
            +
                  "        x.res.redirect('/#{app}/list')",
         
     | 
| 
      
 72 
     | 
    
         
            +
                  "      },",
         
     | 
| 
      
 73 
     | 
    
         
            +
                  "      put: -> (x, id) {",
         
     | 
| 
      
 74 
     | 
    
         
            +
                  "        #{app} = Record.put(x, id, x.req.post)",
         
     | 
| 
      
 75 
     | 
    
         
            +
                  "        return x << #{app}.to_json if x.ext == 'json'",
         
     | 
| 
      
 76 
     | 
    
         
            +
                  "        x.res.redirect('/#{app}/list')",
         
     | 
| 
      
 77 
     | 
    
         
            +
                  "      },",
         
     | 
| 
      
 78 
     | 
    
         
            +
                  "      delete: -> (x, id) {",
         
     | 
| 
      
 79 
     | 
    
         
            +
                  "        Record.delete(x, id)",
         
     | 
| 
      
 80 
     | 
    
         
            +
                  "        return x << {ok: true, id: id}.to_json if x.ext == 'json'",
         
     | 
| 
      
 81 
     | 
    
         
            +
                  "        x.res.redirect('/#{app}/list')",
         
     | 
| 
      
 82 
     | 
    
         
            +
                  "      },",
         
     | 
| 
      
 83 
     | 
    
         
            +
                  "    },",
         
     | 
| 
      
 84 
     | 
    
         
            +
                  "  )",
         
     | 
| 
      
 85 
     | 
    
         
            +
                  "",
         
     | 
| 
      
 86 
     | 
    
         
            +
                  "end",
         
     | 
| 
      
 87 
     | 
    
         
            +
                  "",
         
     | 
| 
      
 88 
     | 
    
         
            +
                ]
         
     | 
| 
      
 89 
     | 
    
         
            +
                File.open(file, 'w'){|f| f.puts re.join("\n") }
         
     | 
| 
      
 90 
     | 
    
         
            +
                puts "Created object file: #{file}"
         
     | 
| 
      
 91 
     | 
    
         
            +
              end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
              def view(folder, app, act, type, columns)
         
     | 
| 
      
 94 
     | 
    
         
            +
                file = "#{folder}/#{act.strip}.rb"
         
     | 
| 
      
 95 
     | 
    
         
            +
                if File.exist? file
         
     | 
| 
      
 96 
     | 
    
         
            +
                  puts "#{file} already exists. Skipping."
         
     | 
| 
      
 97 
     | 
    
         
            +
                  return
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
                # Build the object file
         
     | 
| 
      
 100 
     | 
    
         
            +
                re = [
         
     | 
| 
      
 101 
     | 
    
         
            +
                  "module App::#{Waxx::Util.camel_case(app.strip)}::#{Waxx::Util.camel_case(act.strip)}",
         
     | 
| 
      
 102 
     | 
    
         
            +
                  "  extend Waxx::View",
         
     | 
| 
      
 103 
     | 
    
         
            +
                  "  extend self",
         
     | 
| 
      
 104 
     | 
    
         
            +
                  "",
         
     | 
| 
      
 105 
     | 
    
         
            +
                  "  # Specify what formats this view will render automatically",
         
     | 
| 
      
 106 
     | 
    
         
            +
                  "  as :json",
         
     | 
| 
      
 107 
     | 
    
         
            +
                  "",
         
     | 
| 
      
 108 
     | 
    
         
            +
                  "  # Specify what fields are on this view (only these fields will be rendered and updated)",
         
     | 
| 
      
 109 
     | 
    
         
            +
                  "  has(",
         
     | 
| 
      
 110 
     | 
    
         
            +
                  columns.map{|rec| %(    :#{rec['column_name']},) },
         
     | 
| 
      
 111 
     | 
    
         
            +
                  "  )",
         
     | 
| 
      
 112 
     | 
    
         
            +
                  "",
         
     | 
| 
      
 113 
     | 
    
         
            +
                ]
         
     | 
| 
      
 114 
     | 
    
         
            +
                if type.to_s == 'list'
         
     | 
| 
      
 115 
     | 
    
         
            +
                  re << [
         
     | 
| 
      
 116 
     | 
    
         
            +
                  "  # Add the fields that can be matched with get(x, args: x.req.get)",
         
     | 
| 
      
 117 
     | 
    
         
            +
                  "  match_in(:#{columns[0]['column_name']})",
         
     | 
| 
      
 118 
     | 
    
         
            +
                  "  # Add the fields that can be searched using the 'q' parameter in args",
         
     | 
| 
      
 119 
     | 
    
         
            +
                  "  search_in(:#{columns[1]['column_name']})",
         
     | 
| 
      
 120 
     | 
    
         
            +
                  "",
         
     | 
| 
      
 121 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 122 
     | 
    
         
            +
                end
         
     | 
| 
      
 123 
     | 
    
         
            +
                re << [
         
     | 
| 
      
 124 
     | 
    
         
            +
                  "  # This is the HTML view. Delete this module if you are not rendering HTML.",
         
     | 
| 
      
 125 
     | 
    
         
            +
                  "  module Html",
         
     | 
| 
      
 126 
     | 
    
         
            +
                  "    extend Waxx::Html",
         
     | 
| 
      
 127 
     | 
    
         
            +
                  "    extend self",
         
     | 
| 
      
 128 
     | 
    
         
            +
                  "",
         
     | 
| 
      
 129 
     | 
    
         
            +
                  "    def get(x, #{type == 'record' ? app : 'data'}, message: {})",
         
     | 
| 
      
 130 
     | 
    
         
            +
                  "      title = #{type == 'record' ? "#{app}/:id == 0 ? 'New #{app.capitalize}' : #{app}/:name" : "'#{app.capitalize}s'"}",
         
     | 
| 
      
 131 
     | 
    
         
            +
                  "      App::Html.page(x, title: title, content: #{type}(x, #{type == 'record' ? app: 'data'}), message: message)",
         
     | 
| 
      
 132 
     | 
    
         
            +
                  "    end",
         
     | 
| 
      
 133 
     | 
    
         
            +
                  "",
         
     | 
| 
      
 134 
     | 
    
         
            +
                ]
         
     | 
| 
      
 135 
     | 
    
         
            +
                if type.to_s == 'record'
         
     | 
| 
      
 136 
     | 
    
         
            +
                  re << [
         
     | 
| 
      
 137 
     | 
    
         
            +
                  "    def record(x, #{app})",
         
     | 
| 
      
 138 
     | 
    
         
            +
                  "    %(",
         
     | 
| 
      
 139 
     | 
    
         
            +
                  %(      <form action="/#{app}/#{act}/#{'#{'}#{app}/:id}" method="post">),
         
     | 
| 
      
 140 
     | 
    
         
            +
                  columns.map{|c|
         
     | 
| 
      
 141 
     | 
    
         
            +
                    next if c['pkey']
         
     | 
| 
      
 142 
     | 
    
         
            +
                    %(
         
     | 
| 
      
 143 
     | 
    
         
            +
                    <label for="#{c/:column_name}" class="fssr mt-m">#{c['column_name'].title_case}</label>
         
     | 
| 
      
 144 
     | 
    
         
            +
                    <input id="#{c['column_name']}" name="#{c['column_name']}" class="form" value="#{'#{h '}#{app}/:#{c['column_name']}}">)
         
     | 
| 
      
 145 
     | 
    
         
            +
                  },
         
     | 
| 
      
 146 
     | 
    
         
            +
                  %(        <div class="df g-s">),
         
     | 
| 
      
 147 
     | 
    
         
            +
                  %(          <button type="submit" class="btn btn-primary">Save</button>),
         
     | 
| 
      
 148 
     | 
    
         
            +
                  %(          <a href="/#{app}/list" class="btn">Cancel</a>),
         
     | 
| 
      
 149 
     | 
    
         
            +
                  %(        </div>),
         
     | 
| 
      
 150 
     | 
    
         
            +
                  %(      </form>),
         
     | 
| 
      
 151 
     | 
    
         
            +
                  "    )",
         
     | 
| 
      
 152 
     | 
    
         
            +
                  "    end",
         
     | 
| 
      
 153 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 154 
     | 
    
         
            +
                else
         
     | 
| 
      
 155 
     | 
    
         
            +
                  re << [
         
     | 
| 
      
 156 
     | 
    
         
            +
                  "    def list(x, data)",
         
     | 
| 
      
 157 
     | 
    
         
            +
                  "    %(",
         
     | 
| 
      
 158 
     | 
    
         
            +
                  %(      <a href="/#{app}/record/0" class="fr btn btn-primary">New #{app.title_case}</a>),
         
     | 
| 
      
 159 
     | 
    
         
            +
                  %(      <table class="mt-m data">),
         
     | 
| 
      
 160 
     | 
    
         
            +
                  %(        <thead>),
         
     | 
| 
      
 161 
     | 
    
         
            +
                  %(          <tr>),
         
     | 
| 
      
 162 
     | 
    
         
            +
                  columns.map{|c| %(          <th>#{c['column_name'].title_case}</th>) },
         
     | 
| 
      
 163 
     | 
    
         
            +
                  %(          </tr>),
         
     | 
| 
      
 164 
     | 
    
         
            +
                  %(        </thead>),
         
     | 
| 
      
 165 
     | 
    
         
            +
                  %(        <tbody>),
         
     | 
| 
      
 166 
     | 
    
         
            +
                  '          #{data.map{|rec|',
         
     | 
| 
      
 167 
     | 
    
         
            +
                  '            %(',
         
     | 
| 
      
 168 
     | 
    
         
            +
                  '            <tr>',
         
     | 
| 
      
 169 
     | 
    
         
            +
                  columns.map{|c| %(              <td>#{'#{h rec/:'}#{c['column_name']}}</td>) },
         
     | 
| 
      
 170 
     | 
    
         
            +
                  %(              <td><a href="/#{app}/record/#{'#{'}rec/:id}">edit</a></td>),
         
     | 
| 
      
 171 
     | 
    
         
            +
                  '            </tr>',
         
     | 
| 
      
 172 
     | 
    
         
            +
                  '            )',
         
     | 
| 
      
 173 
     | 
    
         
            +
                  '          }.join("\n")}',
         
     | 
| 
      
 174 
     | 
    
         
            +
                  %(        </tbody>),
         
     | 
| 
      
 175 
     | 
    
         
            +
                  %(      </table>),
         
     | 
| 
      
 176 
     | 
    
         
            +
                  "    )",
         
     | 
| 
      
 177 
     | 
    
         
            +
                  "    end",
         
     | 
| 
      
 178 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 179 
     | 
    
         
            +
                end
         
     | 
| 
      
 180 
     | 
    
         
            +
                re << "  end"
         
     | 
| 
      
 181 
     | 
    
         
            +
                re << "end"
         
     | 
| 
      
 182 
     | 
    
         
            +
                # Write the view file
         
     | 
| 
      
 183 
     | 
    
         
            +
                File.open(file, 'w'){|f| f.puts re.join("\n") }
         
     | 
| 
      
 184 
     | 
    
         
            +
                # Require the view file from the object file
         
     | 
| 
      
 185 
     | 
    
         
            +
                File.open("#{folder}/#{app}.rb", 'a'){|f| f.puts %(require_relative "#{act}") }
         
     | 
| 
      
 186 
     | 
    
         
            +
                puts "Created view file: #{file}"
         
     | 
| 
      
 187 
     | 
    
         
            +
              end
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/waxx/http.rb
    CHANGED
    
    | 
         @@ -25,9 +25,10 @@ module Waxx::Http 
     | 
|
| 
       25 
25 
     | 
    
         
             
              alias qs escape
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
              def unescape(str)
         
     | 
| 
       28 
     | 
    
         
            -
                str.to_s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/) do |m|
         
     | 
| 
      
 28 
     | 
    
         
            +
                s = str.to_s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/) do |m|
         
     | 
| 
       29 
29 
     | 
    
         
             
                  [m.delete('%')].pack('H*')
         
     | 
| 
       30 
     | 
    
         
            -
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
                end.force_encoding('UTF-8')
         
     | 
| 
      
 31 
     | 
    
         
            +
            	  s.valid_encoding? ? s : s.force_encoding(str.encoding)
         
     | 
| 
       31 
32 
     | 
    
         
             
              end
         
     | 
| 
       32 
33 
     | 
    
         | 
| 
       33 
34 
     | 
    
         
             
              def parse_head(io)
         
     | 
| 
         @@ -38,7 +39,7 @@ module Waxx::Http 
     | 
|
| 
       38 
39 
     | 
    
         
             
                  break if e.strip == ""
         
     | 
| 
       39 
40 
     | 
    
         
             
                  head << e
         
     | 
| 
       40 
41 
     | 
    
         
             
                  n, v = e.split(":", 2)
         
     | 
| 
       41 
     | 
    
         
            -
                  env[n] = v.strip
         
     | 
| 
      
 42 
     | 
    
         
            +
                  env[n.downcase] = v.strip
         
     | 
| 
       42 
43 
     | 
    
         
             
                end
         
     | 
| 
       43 
44 
     | 
    
         
             
                Waxx.debug "env.size: #{env.size}", 9
         
     | 
| 
       44 
45 
     | 
    
         
             
                [env, head]
         
     | 
| 
         @@ -46,7 +47,7 @@ module Waxx::Http 
     | 
|
| 
       46 
47 
     | 
    
         | 
| 
       47 
48 
     | 
    
         
             
              def query_string_to_hash(str, base={})
         
     | 
| 
       48 
49 
     | 
    
         
             
                return base if str.nil? or str.strip == ""
         
     | 
| 
       49 
     | 
    
         
            -
                str.strip.split(/[;&]/).each{|nv|
         
     | 
| 
      
 50 
     | 
    
         
            +
                str.force_encoding('UTF-8').strip.split(/[;&]/).each{|nv|
         
     | 
| 
       50 
51 
     | 
    
         
             
                  n, v = nv.split("=",2).map{|s| unescape(s)}
         
     | 
| 
       51 
52 
     | 
    
         
             
                  if n =~ /\[\]$/
         
     | 
| 
       52 
53 
     | 
    
         
             
                    n = n.sub(/\[\]$/,"")
         
     | 
| 
         @@ -59,25 +60,55 @@ module Waxx::Http 
     | 
|
| 
       59 
60 
     | 
    
         
             
                base
         
     | 
| 
       60 
61 
     | 
    
         
             
              end
         
     | 
| 
       61 
62 
     | 
    
         | 
| 
      
 63 
     | 
    
         
            +
              def file_object(boundary, filename, body, headers)
         
     | 
| 
      
 64 
     | 
    
         
            +
                {
         
     | 
| 
      
 65 
     | 
    
         
            +
                  filename: filename,
         
     | 
| 
      
 66 
     | 
    
         
            +
                  data: body.sub(/\r\n--#{boundary}--\r\n$/,"").sub(/\r\n$/,""),
         
     | 
| 
      
 67 
     | 
    
         
            +
                  content_type: headers['content-type'] || headers['Content-Type'],
         
     | 
| 
      
 68 
     | 
    
         
            +
                  headers: headers
         
     | 
| 
      
 69 
     | 
    
         
            +
                }
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
       62 
72 
     | 
    
         
             
              def parse_multipart(env, data)
         
     | 
| 
       63 
     | 
    
         
            -
                boundary = env[' 
     | 
| 
      
 73 
     | 
    
         
            +
                boundary = env['content-type'].match(/boundary=(.*)$/)[1]
         
     | 
| 
       64 
74 
     | 
    
         
             
                parts = data.split("--"+boundary+"\r\n")
         
     | 
| 
       65 
75 
     | 
    
         
             
                post = {}
         
     | 
| 
       66 
76 
     | 
    
         
             
                parts.each{|part|
         
     | 
| 
       67 
77 
     | 
    
         
             
                  next if part.strip == ""
         
     | 
| 
       68 
78 
     | 
    
         
             
                  begin
         
     | 
| 
       69 
79 
     | 
    
         
             
                    head, body = part.split("\r\n\r\n",2)
         
     | 
| 
       70 
     | 
    
         
            -
                    headers = Hash[*(head.split("\r\n").map{|hp| 
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
      
 80 
     | 
    
         
            +
                    headers = Hash[*(head.split("\r\n").map{|hp|
         
     | 
| 
      
 81 
     | 
    
         
            +
                      hp.split(":",2).map{|i| i.strip}
         
     | 
| 
      
 82 
     | 
    
         
            +
                    }.flatten)]
         
     | 
| 
      
 83 
     | 
    
         
            +
                    cd = Hash[*("_=#{headers['Content-Disposition'] || headers['content-disposition']}".split(";").map{|da| da.strip.gsub('"',"").split("=",2)}.flatten)]
         
     | 
| 
      
 84 
     | 
    
         
            +
                    name = cd['name']
         
     | 
| 
      
 85 
     | 
    
         
            +
                    # If field name ends with [], make result an array
         
     | 
| 
      
 86 
     | 
    
         
            +
                    if name.include?('[]')
         
     | 
| 
      
 87 
     | 
    
         
            +
                      # Strip the square backets off the name for the post key
         
     | 
| 
      
 88 
     | 
    
         
            +
                      name = name.sub(/\[\]$/,'')
         
     | 
| 
      
 89 
     | 
    
         
            +
                      post[name] ||= []
         
     | 
| 
      
 90 
     | 
    
         
            +
                    end
         
     | 
| 
       72 
91 
     | 
    
         
             
                    if cd['filename']
         
     | 
| 
       73 
     | 
    
         
            -
                       
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
                         
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
                         
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
      
 92 
     | 
    
         
            +
                      # Handle multiple files
         
     | 
| 
      
 93 
     | 
    
         
            +
                      if post.has_key?(name)
         
     | 
| 
      
 94 
     | 
    
         
            +
                        if Array === post[name]
         
     | 
| 
      
 95 
     | 
    
         
            +
                          post[name].push file_object(boundary, cd['filename'], body, headers)
         
     | 
| 
      
 96 
     | 
    
         
            +
                        else
         
     | 
| 
      
 97 
     | 
    
         
            +
                          post[name] = [post[name], file_object(boundary, cd['filename'], body, headers)]
         
     | 
| 
      
 98 
     | 
    
         
            +
                        end
         
     | 
| 
      
 99 
     | 
    
         
            +
                      else
         
     | 
| 
      
 100 
     | 
    
         
            +
                        post[name] = file_object(boundary, cd['filename'], body, headers)
         
     | 
| 
      
 101 
     | 
    
         
            +
                      end
         
     | 
| 
       79 
102 
     | 
    
         
             
                    else
         
     | 
| 
       80 
     | 
    
         
            -
                      post 
     | 
| 
      
 103 
     | 
    
         
            +
                      if post.has_key?(name)
         
     | 
| 
      
 104 
     | 
    
         
            +
                        if Array === post[name]
         
     | 
| 
      
 105 
     | 
    
         
            +
                          post[name].push body.sub(/\r\n--#{boundary}--\r\n$/,"").sub(/\r\n$/,"")
         
     | 
| 
      
 106 
     | 
    
         
            +
                        else
         
     | 
| 
      
 107 
     | 
    
         
            +
                          post[name] = [post[name], body.sub(/\r\n--#{boundary}--\r\n$/,"").sub(/\r\n$/,"")]
         
     | 
| 
      
 108 
     | 
    
         
            +
                        end
         
     | 
| 
      
 109 
     | 
    
         
            +
                      else
         
     | 
| 
      
 110 
     | 
    
         
            +
                        post[name] = body.sub(/\r\n--#{boundary}--\r\n$/,"").sub(/\r\n$/,"")
         
     | 
| 
      
 111 
     | 
    
         
            +
                      end
         
     | 
| 
       81 
112 
     | 
    
         
             
                    end
         
     | 
| 
       82 
113 
     | 
    
         
             
                  rescue => e
         
     | 
| 
       83 
114 
     | 
    
         
             
                    Waxx.debug "Error parse_multipart: #{e}"
         
     | 
| 
         @@ -113,30 +144,41 @@ module Waxx::Http 
     | 
|
| 
       113 
144 
     | 
    
         
             
              end
         
     | 
| 
       114 
145 
     | 
    
         | 
| 
       115 
146 
     | 
    
         
             
              def parse_data(env, meth, io, head)
         
     | 
| 
       116 
     | 
    
         
            -
                 
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
                   
     | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
      
 147 
     | 
    
         
            +
                begin
         
     | 
| 
      
 148 
     | 
    
         
            +
                  Waxx.debug "parse_data"
         
     | 
| 
      
 149 
     | 
    
         
            +
                  if %w(PUT POST PATCH).include? meth
         
     | 
| 
      
 150 
     | 
    
         
            +
                    data = io.read(env['content-length'].to_i)
         
     | 
| 
      
 151 
     | 
    
         
            +
                    Waxx.debug "data.size: #{data.size} #{env['content-type']}"
         
     | 
| 
      
 152 
     | 
    
         
            +
                    # No content
         
     | 
| 
      
 153 
     | 
    
         
            +
                    if env['content-length'].to_i == 0
         
     | 
| 
      
 154 
     | 
    
         
            +
                      post = {}.freeze
         
     | 
| 
      
 155 
     | 
    
         
            +
                      data = nil
         
     | 
| 
      
 156 
     | 
    
         
            +
                    # Raw file saved by nginx with path in header
         
     | 
| 
      
 157 
     | 
    
         
            +
                    elsif env['x-file-path']
         
     | 
| 
      
 158 
     | 
    
         
            +
                      post = {}.freeze
         
     | 
| 
      
 159 
     | 
    
         
            +
                      data = {"file_path" => env['x-file-path']}
         
     | 
| 
      
 160 
     | 
    
         
            +
                    # Parse based on content type
         
     | 
| 
      
 161 
     | 
    
         
            +
                    else
         
     | 
| 
      
 162 
     | 
    
         
            +
                      case env['content-type']
         
     | 
| 
      
 163 
     | 
    
         
            +
                        when /x-www-form-urlencoded/
         
     | 
| 
      
 164 
     | 
    
         
            +
                          post = query_string_to_hash(data).freeze
         
     | 
| 
      
 165 
     | 
    
         
            +
                        when /multipart/
         
     | 
| 
      
 166 
     | 
    
         
            +
                          post = parse_multipart(env, data).freeze
         
     | 
| 
      
 167 
     | 
    
         
            +
                        when /json/
         
     | 
| 
      
 168 
     | 
    
         
            +
                          post = (JSON.parse(data)).freeze
         
     | 
| 
      
 169 
     | 
    
         
            +
                        else
         
     | 
| 
      
 170 
     | 
    
         
            +
                          post = {"data" => data}.freeze
         
     | 
| 
      
 171 
     | 
    
         
            +
                      end
         
     | 
| 
      
 172 
     | 
    
         
            +
                    end
         
     | 
| 
      
 173 
     | 
    
         
            +
                  else
         
     | 
| 
       121 
174 
     | 
    
         
             
                    post = {}.freeze
         
     | 
| 
       122 
175 
     | 
    
         
             
                    data = nil
         
     | 
| 
       123 
     | 
    
         
            -
                  else
         
     | 
| 
       124 
     | 
    
         
            -
                    case (env['Content-Type'] || env['content-type'] || env['Content-type'])
         
     | 
| 
       125 
     | 
    
         
            -
                      when /x-www-form-urlencoded/
         
     | 
| 
       126 
     | 
    
         
            -
                        post = query_string_to_hash(data).freeze
         
     | 
| 
       127 
     | 
    
         
            -
                      when /multipart/
         
     | 
| 
       128 
     | 
    
         
            -
                        post = parse_multipart(env, data).freeze
         
     | 
| 
       129 
     | 
    
         
            -
                      when /json/
         
     | 
| 
       130 
     | 
    
         
            -
                        post = (JSON.parse(data)).freeze
         
     | 
| 
       131 
     | 
    
         
            -
                      else
         
     | 
| 
       132 
     | 
    
         
            -
                        post = data.freeze
         
     | 
| 
       133 
     | 
    
         
            -
                    end
         
     | 
| 
       134 
176 
     | 
    
         
             
                  end
         
     | 
| 
       135 
     | 
    
         
            -
             
     | 
| 
       136 
     | 
    
         
            -
             
     | 
| 
       137 
     | 
    
         
            -
                  data  
     | 
| 
      
 177 
     | 
    
         
            +
                  [post, data]
         
     | 
| 
      
 178 
     | 
    
         
            +
                rescue => e
         
     | 
| 
      
 179 
     | 
    
         
            +
                  Waxx.debug("ERROR: Parsing POST data: #{e}")
         
     | 
| 
      
 180 
     | 
    
         
            +
                  [{error: e.to_s}.freeze, nil]
         
     | 
| 
       138 
181 
     | 
    
         
             
                end
         
     | 
| 
       139 
     | 
    
         
            -
                [post, data]
         
     | 
| 
       140 
182 
     | 
    
         
             
              end
         
     | 
| 
       141 
183 
     | 
    
         | 
| 
       142 
184 
     | 
    
         
             
              Status = {
         
     | 
| 
         @@ -169,6 +211,7 @@ module Waxx::Http 
     | 
|
| 
       169 
211 
     | 
    
         
             
                js:      "application/javascript; charset=utf-8",
         
     | 
| 
       170 
212 
     | 
    
         
             
                json:    "application/json; charset=utf-8",
         
     | 
| 
       171 
213 
     | 
    
         
             
                tab:     "text/tab-separated-values; charset=utf-8",
         
     | 
| 
      
 214 
     | 
    
         
            +
                tsv:     "text/tab-separated-values; charset=utf-8",
         
     | 
| 
       172 
215 
     | 
    
         
             
                txt:     "text/plain; charset=utf-8",
         
     | 
| 
       173 
216 
     | 
    
         
             
                xml:     "text/xml",                              
         
     | 
| 
       174 
217 
     | 
    
         
             
                gif:     "image/gif",                             
         
     | 
    
        data/lib/waxx/init.rb
    CHANGED
    
    | 
         @@ -182,7 +182,7 @@ init: 
     | 
|
| 
       182 
182 
     | 
    
         
             
                  puts "The databse must already exist and the user must have create table privileges."
         
     | 
| 
       183 
183 
     | 
    
         
             
                  print "  Create waxx table (y|n) [y]:"
         
     | 
| 
       184 
184 
     | 
    
         
             
                  initdb = $stdin.gets.chomp
         
     | 
| 
       185 
     | 
    
         
            -
                  initdb = initdb == '' or not (initdb =~ /[Yy]/).nil?
         
     | 
| 
      
 185 
     | 
    
         
            +
                  initdb = initdb == '' or not (initdb =~ /[Yy]/).nil? rescue false
         
     | 
| 
       186 
186 
     | 
    
         
             
                  input['init']['db'] = initdb
         
     | 
| 
       187 
187 
     | 
    
         
             
                end
         
     | 
| 
       188 
188 
     | 
    
         
             
                input
         
     | 
| 
         @@ -235,6 +235,7 @@ init: 
     | 
|
| 
       235 
235 
     | 
    
         
             
                puts ""
         
     | 
| 
       236 
236 
     | 
    
         
             
                puts "Waxx installed successfully."
         
     | 
| 
       237 
237 
     | 
    
         
             
                puts "cd into #{install_folder} and run `waxx on` to get your waxx on"
         
     | 
| 
      
 238 
     | 
    
         
            +
                puts "Optionally run `waxx gen app TABLE_NAME` where TABLE_NAME is the name of a table in your database."
         
     | 
| 
       238 
239 
     | 
    
         
             
              end
         
     | 
| 
       239 
240 
     | 
    
         | 
| 
       240 
241 
     | 
    
         
             
              def create_waxx_table(x, input)
         
     | 
| 
         @@ -254,7 +255,7 @@ init: 
     | 
|
| 
       254 
255 
     | 
    
         
             
                    CONSTRAINT waxx_uniq UNIQUE(name)
         
     | 
| 
       255 
256 
     | 
    
         
             
                  )
         
     | 
| 
       256 
257 
     | 
    
         
             
                )
         
     | 
| 
       257 
     | 
    
         
            -
                insert_sql = %(INSERT INTO waxx (name, value) VALUES ('db. 
     | 
| 
      
 258 
     | 
    
         
            +
                insert_sql = %(INSERT INTO waxx (name, value) VALUES ('db.migration.last', '0'))
         
     | 
| 
       258 
259 
     | 
    
         
             
                puts "  Connecting to: #{input/:databases/:app}"
         
     | 
| 
       259 
260 
     | 
    
         
             
                begin
         
     | 
| 
       260 
261 
     | 
    
         
             
                  db = Waxx::Database.connect(input/:databases/:app)
         
     | 
    
        data/lib/waxx/object.rb
    CHANGED
    
    | 
         @@ -59,11 +59,11 @@ module Waxx::Object 
     | 
|
| 
       59 
59 
     | 
    
         
             
              # # A proc that return boolean (true = access granted, false = access denied)
         
     | 
| 
       60 
60 
     | 
    
         
             
              # # The x variable is passed in.
         
     | 
| 
       61 
61 
     | 
    
         
             
              # acl: -> (x) { 
         
     | 
| 
       62 
     | 
    
         
            -
              #   x.req.env[' 
     | 
| 
      
 62 
     | 
    
         
            +
              #   x.req.env['x-key'] == "Secret Key"
         
     | 
| 
       63 
63 
     | 
    
         
             
              # }
         
     | 
| 
       64 
64 
     | 
    
         
             
              # # Another example based on the client IP set by the proxy server
         
     | 
| 
       65 
65 
     | 
    
         
             
              # acl: -> (x) { 
         
     | 
| 
       66 
     | 
    
         
            -
              #   [x.req.env[' 
     | 
| 
      
 66 
     | 
    
         
            +
              #   [x.req.env['x-forwarded-for']].flatten.first == "10.20.40.80"
         
     | 
| 
       67 
67 
     | 
    
         
             
              # }
         
     | 
| 
       68 
68 
     | 
    
         
             
              # # Require a user to be in two groups
         
     | 
| 
       69 
69 
     | 
    
         
             
              # acl: -> (x) { 
         
     |