apex 0.0.2 → 0.0.3
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 +146 -3
- data/lib/apex/request.rb +26 -2
- data/lib/apex/server.rb +36 -9
- data/lib/apex/version.rb +1 -1
- data/spec/unit/request_get_spec.rb +89 -0
- metadata +5 -46
- data/spec/main_spec.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67fa319a7be6930bdb57ed1225ec9a85ac34e58c
|
4
|
+
data.tar.gz: c2145e383269e800c13a603ad9b4169684cf5a45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 556f7b5edc3cadf511de37be894a3f575d2e9a63efa9294b54e0f8989d7c8c372682890110779e63e252b7c06f04bc6cf9a44335de6a9ab9717a8f22b89de236
|
7
|
+
data.tar.gz: 494d533192637b923e3e62f58c735c1b64214402467c38cc208cbde1325888c691af1be6ed42e5bb0265a250773d8abdc149eae28eb12187e6f5976c1b4ab247
|
data/README.md
CHANGED
@@ -4,14 +4,14 @@ Apex is a RubyMotion web framework for OS X. It uses
|
|
4
4
|
GCDWebServer under the hood and provides a Sinatra-like
|
5
5
|
router and DSL.
|
6
6
|
|
7
|
-
Apex is currently experimental and in development.
|
8
|
-
|
7
|
+
Apex is currently experimental and in development. Let me know
|
8
|
+
what you think [on Twitter](http://twitter.com/jamonholmgren).
|
9
9
|
|
10
10
|
## Installation
|
11
11
|
|
12
12
|
```ruby
|
13
13
|
# In Gemfile:
|
14
|
-
gem 'apex'
|
14
|
+
gem 'apex', :git => 'https://github.com/clearsightstudio/apex.git
|
15
15
|
|
16
16
|
# In Terminal:
|
17
17
|
bundle install
|
@@ -20,6 +20,8 @@ rake pod:install
|
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
|
23
|
+
### Using your AppDelegate
|
24
|
+
|
23
25
|
```ruby
|
24
26
|
class AppDelegate < Apex::Server
|
25
27
|
port 8080 # defaults to 8080
|
@@ -50,6 +52,147 @@ class AppDelegate < Apex::Server
|
|
50
52
|
end
|
51
53
|
```
|
52
54
|
|
55
|
+
#### Alternate Railsy Syntax
|
56
|
+
|
57
|
+
This is under consideration.
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
class AppDelegate < Apex::Server
|
61
|
+
def routes
|
62
|
+
get "/", controller: HomeController, action: :home
|
63
|
+
get "/about", controller: AboutController, action: :about
|
64
|
+
get "/about/me", controller: AboutController, action: :me
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class HomeController < Apex::Controller
|
69
|
+
def home
|
70
|
+
render :home, layout: DefaultLayout
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class AboutController < Apex::Controller
|
75
|
+
layout AboutLayout
|
76
|
+
|
77
|
+
def about
|
78
|
+
render :about
|
79
|
+
end
|
80
|
+
|
81
|
+
def me
|
82
|
+
render :me, name: "Jamon"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def AboutView < Apex::View
|
87
|
+
def about
|
88
|
+
"<h1>About</h1>"
|
89
|
+
end
|
90
|
+
|
91
|
+
def me(args={})
|
92
|
+
"<h1>Me #{args[:name]}</h1>"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def AboutLayout < Apex::Layout
|
97
|
+
def render
|
98
|
+
"<html>" +
|
99
|
+
"<head>" +
|
100
|
+
"<title>#{title}</title>" +
|
101
|
+
"</head>" +
|
102
|
+
"<body>#{content}</body>" +
|
103
|
+
"</html>"
|
104
|
+
end
|
105
|
+
|
106
|
+
# Potentially, a Ruby DSL for HTML:
|
107
|
+
def render
|
108
|
+
html do
|
109
|
+
head do
|
110
|
+
title "My title"
|
111
|
+
end
|
112
|
+
body do
|
113
|
+
content_for :body
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
```
|
119
|
+
|
120
|
+
### Standalone class
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
|
124
|
+
class WebServer < Apex::Server
|
125
|
+
port 8080 # defaults to 8080
|
126
|
+
|
127
|
+
layout do
|
128
|
+
"<html>" +
|
129
|
+
"<head><title>Apex</title></head>" +
|
130
|
+
"<body>" +
|
131
|
+
content +
|
132
|
+
"</body>" +
|
133
|
+
"</html>"
|
134
|
+
end
|
135
|
+
|
136
|
+
get "/" do |r|
|
137
|
+
"<h1>Apex is running. Response: #{r}</h1>" +
|
138
|
+
"<p><a href='/about'>About Apex</a></p>"
|
139
|
+
end
|
140
|
+
|
141
|
+
get "/about" do |r|
|
142
|
+
"<h1>About Apex</h1>" +
|
143
|
+
"<p><a href='/'>Home</a></p>"
|
144
|
+
end
|
145
|
+
|
146
|
+
post "/some_post" do |request|
|
147
|
+
request.headers["User-Agent"]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
```
|
151
|
+
|
152
|
+
Then in your AppDelegate (or wherever you'd like to start your server):
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
@server = WebServer.new
|
156
|
+
@server.start_server
|
157
|
+
```
|
158
|
+
|
159
|
+
## JSON
|
160
|
+
|
161
|
+
You can also return json. You can specify the response_type, like so:
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
get "/current_user", response_type: :json do |request|
|
165
|
+
{
|
166
|
+
name: 'Todd',
|
167
|
+
age: 21
|
168
|
+
}
|
169
|
+
end
|
170
|
+
```
|
171
|
+
|
172
|
+
Or it will auto-detect the repsonse type if you return a hash instead of a string:
|
173
|
+
```ruby
|
174
|
+
get "/current_user" do |request|
|
175
|
+
{
|
176
|
+
name: 'Todd',
|
177
|
+
age: 21
|
178
|
+
}
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
## Benchmarking
|
183
|
+
|
184
|
+
Somewhat useless (but still fun) benchmarking against a minimal Node.js/Express app
|
185
|
+
shows Apex serving requests about 1.4x as fast as Node.
|
186
|
+
|
187
|
+
```sh-session
|
188
|
+
# Node.js / express.js app found in ./benchmarks/node/app.js
|
189
|
+
$ ab -r -n 10000 -c 6 -r http://192.168.1.246:8081/benchmark | grep "Requests per second"
|
190
|
+
Requests per second: 2789.32 [#/sec] (mean)
|
191
|
+
# Apex server found in ./app/app_delegate.rb
|
192
|
+
$ ab -r -n 10000 -c 6 -r http://192.168.1.246:8080/benchmark | grep "Requests per second"
|
193
|
+
Requests per second: 3862.26 [#/sec] (mean)
|
194
|
+
```
|
195
|
+
|
53
196
|
## Contributing
|
54
197
|
|
55
198
|
1. Fork it
|
data/lib/apex/request.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Apex
|
2
2
|
class Request
|
3
|
+
HEADER_PARAM = /\s*[\w.]+=(?:[\w.]+|"(?:[^"\\]|\\.)*")?\s*/
|
4
|
+
HEADER_VALUE_WITH_PARAMS = /(?:(?:\w+|\*)\/(?:\w+(?:\.|\-|\+)?|\*)*)\s*(?:;#{HEADER_PARAM})*/
|
5
|
+
|
3
6
|
attr_accessor :raw
|
4
7
|
|
5
8
|
def initialize(raw)
|
@@ -26,6 +29,7 @@ module Apex
|
|
26
29
|
def query
|
27
30
|
raw.query
|
28
31
|
end
|
32
|
+
alias_method :params, :query
|
29
33
|
|
30
34
|
def path
|
31
35
|
raw.path
|
@@ -35,8 +39,28 @@ module Apex
|
|
35
39
|
raw.URL
|
36
40
|
end
|
37
41
|
|
38
|
-
def
|
39
|
-
|
42
|
+
def method
|
43
|
+
raw.method
|
44
|
+
end
|
45
|
+
|
46
|
+
def get?
|
47
|
+
method == "GET"
|
48
|
+
end
|
49
|
+
|
50
|
+
def post?
|
51
|
+
method == "POST"
|
52
|
+
end
|
53
|
+
|
54
|
+
def put?
|
55
|
+
method == "PUT"
|
56
|
+
end
|
57
|
+
|
58
|
+
def patch?
|
59
|
+
method == "PATCH"
|
60
|
+
end
|
61
|
+
|
62
|
+
def delete?
|
63
|
+
method == "DELETE"
|
40
64
|
end
|
41
65
|
|
42
66
|
end
|
data/lib/apex/server.rb
CHANGED
@@ -3,6 +3,11 @@ module Apex
|
|
3
3
|
include DelegateInterface
|
4
4
|
|
5
5
|
def on_launch
|
6
|
+
start_server
|
7
|
+
end
|
8
|
+
|
9
|
+
def start_server
|
10
|
+
return true if RUBYMOTION_ENV == "test"
|
6
11
|
add_static_handler
|
7
12
|
add_app_handlers
|
8
13
|
start
|
@@ -27,14 +32,36 @@ module Apex
|
|
27
32
|
processBlock: -> (raw_request) {
|
28
33
|
layout = false
|
29
34
|
request = Request.new(raw_request)
|
30
|
-
if
|
35
|
+
if (routes_verb = self.routes[verb]) &&
|
36
|
+
(request_path = routes_verb[request.path]) &&
|
37
|
+
(response_block = request_path[:handler])
|
38
|
+
|
31
39
|
request_args = [request].first(response_block.arity)
|
32
40
|
response = response_block.call(*request_args)
|
33
|
-
layout =
|
41
|
+
layout = request_path[:layout]
|
42
|
+
|
43
|
+
unless response_type = request_path[:response_type]
|
44
|
+
case response # Auto detect
|
45
|
+
when Hash
|
46
|
+
response_type = :json
|
47
|
+
else
|
48
|
+
response_type = :html
|
49
|
+
# TODO, do the the rest of the types
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
case response_type
|
54
|
+
when :html
|
55
|
+
GCDWebServerDataResponse.responseWithHTML(apply_layout(response, layout))
|
56
|
+
when :json
|
57
|
+
GCDWebServerDataResponse.responseWithJSONObject(apply_layout(response, layout))
|
58
|
+
# TODO, do the the rest of the types
|
59
|
+
end
|
60
|
+
|
34
61
|
else
|
35
62
|
response = "<h1>404 not found</h1>"
|
63
|
+
GCDWebServerDataResponse.responseWithHTML(apply_layout(response, layout))
|
36
64
|
end
|
37
|
-
GCDWebServerDataResponse.responseWithHTML apply_layout(response, layout)
|
38
65
|
}
|
39
66
|
)
|
40
67
|
end
|
@@ -50,29 +77,29 @@ module Apex
|
|
50
77
|
end
|
51
78
|
|
52
79
|
def start
|
53
|
-
server.
|
80
|
+
server.startWithPort self.class.port, bonjourName: nil
|
54
81
|
end
|
55
82
|
|
56
83
|
# Class methods *************************
|
57
84
|
|
58
85
|
def self.get(path, args={}, &block)
|
59
|
-
routes[:get][path] = { handler: block, layout: args[:layout] }
|
86
|
+
routes[:get][path] = { handler: block, layout: args[:layout], response_type: args[:response_type] }
|
60
87
|
end
|
61
88
|
|
62
89
|
def self.post(path, args={}, &block)
|
63
|
-
routes[:post][path] = { handler: block, layout: args[:layout] }
|
90
|
+
routes[:post][path] = { handler: block, layout: args[:layout], response_type: args[:response_type] }
|
64
91
|
end
|
65
92
|
|
66
93
|
def self.put(path, args={}, &block)
|
67
|
-
routes[:put][path] = { handler: block, layout: args[:layout] }
|
94
|
+
routes[:put][path] = { handler: block, layout: args[:layout], response_type: args[:response_type] }
|
68
95
|
end
|
69
96
|
|
70
97
|
def self.patch(path, args={}, &block)
|
71
|
-
routes[:patch][path] = { handler: block, layout: args[:layout] }
|
98
|
+
routes[:patch][path] = { handler: block, layout: args[:layout], response_type: args[:response_type] }
|
72
99
|
end
|
73
100
|
|
74
101
|
def self.delete(path, args={}, &block)
|
75
|
-
routes[:delete][path] = { handler: block, layout: args[:layout] }
|
102
|
+
routes[:delete][path] = { handler: block, layout: args[:layout], response_type: args[:response_type] }
|
76
103
|
end
|
77
104
|
|
78
105
|
def self.routes
|
data/lib/apex/version.rb
CHANGED
@@ -0,0 +1,89 @@
|
|
1
|
+
describe "Apex::Request GET request" do
|
2
|
+
|
3
|
+
def headers
|
4
|
+
{
|
5
|
+
"Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
6
|
+
"Accept-Encoding" => "gzip,deflate,sdch",
|
7
|
+
"Cookie" => "user_id=USER_ID; __atuvc=0%7C17",
|
8
|
+
"Host" => "localhost:8080",
|
9
|
+
"User-Agent" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36",
|
10
|
+
"Accept-Language" => "en-US,en;q=0.8,sk;q=0.6,es;q=0.4",
|
11
|
+
"Cache-Control" => "max-age=0",
|
12
|
+
"Connection" => "keep-alive"
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def query
|
17
|
+
{ "test" => "tested" }
|
18
|
+
end
|
19
|
+
|
20
|
+
def raw_request
|
21
|
+
@raw_request ||= GCDWebServerRequest.alloc.initWithMethod("GET", url: "http://localhost:8080", headers: headers, path:"/benchmark", query: query)
|
22
|
+
end
|
23
|
+
|
24
|
+
def request
|
25
|
+
@request ||= Apex::Request.new(raw_request)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "#raw" do
|
29
|
+
request.raw.should == raw_request
|
30
|
+
end
|
31
|
+
|
32
|
+
it "#body?" do
|
33
|
+
request.body?.should.be.false
|
34
|
+
end
|
35
|
+
|
36
|
+
it "#content_type" do
|
37
|
+
request.content_type.should.be.nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "#headers" do
|
41
|
+
request.headers.should == headers
|
42
|
+
end
|
43
|
+
|
44
|
+
it "#content_length" do
|
45
|
+
request.content_length.should == 9223372036854775807
|
46
|
+
end
|
47
|
+
|
48
|
+
it "#query" do
|
49
|
+
request.query.should == query
|
50
|
+
end
|
51
|
+
|
52
|
+
it "#path" do
|
53
|
+
request.path.should == "/benchmark"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "#url" do
|
57
|
+
request.url.should == "http://localhost:8080"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "#params" do
|
61
|
+
request.query.should == query
|
62
|
+
request.params.should == query
|
63
|
+
end
|
64
|
+
|
65
|
+
it "#method" do
|
66
|
+
request.method.should == "GET"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "#get?" do
|
70
|
+
request.get?.should.be.true
|
71
|
+
end
|
72
|
+
|
73
|
+
it "#post?" do
|
74
|
+
request.post?.should.be.false
|
75
|
+
end
|
76
|
+
|
77
|
+
it "#put?" do
|
78
|
+
request.put?.should.be.false
|
79
|
+
end
|
80
|
+
|
81
|
+
it "#patch?" do
|
82
|
+
request.patch?.should.be.false
|
83
|
+
end
|
84
|
+
|
85
|
+
it "#delete?" do
|
86
|
+
request.delete?.should.be.false
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamon Holmgren
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: motion-cocoapods
|
@@ -24,48 +24,6 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.5.0
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: webstub
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '1.0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '1.0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: motion-stump
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0.3'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0.3'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: motion-redgreen
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0.1'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0.1'
|
69
27
|
- !ruby/object:Gem::Dependency
|
70
28
|
name: rake
|
71
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,7 +53,7 @@ files:
|
|
95
53
|
- lib/apex/response.rb
|
96
54
|
- lib/apex/server.rb
|
97
55
|
- lib/apex/version.rb
|
98
|
-
- spec/
|
56
|
+
- spec/unit/request_get_spec.rb
|
99
57
|
homepage: https://github.com/clearsightstudio/apex
|
100
58
|
licenses:
|
101
59
|
- MIT
|
@@ -122,4 +80,5 @@ specification_version: 4
|
|
122
80
|
summary: Apex is a RubyMotion web framework for OS X. It uses GCDWebServer under the
|
123
81
|
hood and provides a Sinatra-like router and DSL.
|
124
82
|
test_files:
|
125
|
-
- spec/
|
83
|
+
- spec/unit/request_get_spec.rb
|
84
|
+
has_rdoc:
|