apex 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5ce8882c6a877b50d8b2fbbe8db5469d03d6b657
4
- data.tar.gz: a815007e4186159f5ce2afb1e26a9b8dd37b9fb6
3
+ metadata.gz: 67fa319a7be6930bdb57ed1225ec9a85ac34e58c
4
+ data.tar.gz: c2145e383269e800c13a603ad9b4169684cf5a45
5
5
  SHA512:
6
- metadata.gz: f8903362700a01513fdcca170ee89109ccb8f401e8340f5898bd96eac3cf4b45144425774ca09210738365003678420b580d449f6ebfda0829321acf0c9b3ec6
7
- data.tar.gz: a4aa2357797d5ce7e404928c6fdb5a39abe4eeaf9061f9dbd999e3c586cef82cdee30da8c4d681852ad716640692b0da323acbc5ea87384f49d83c91b75c67c1
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. I'd
8
- love to have help; feel free get in touch [on Twitter](http://twitter.com/jamonholmgren).
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
@@ -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 url_string
39
- url.absoluteString
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
@@ -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 response_block = self.routes[verb][request.path][:handler] rescue nil
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 = self.routes[verb][request.path][: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.runWithPort self.class.port, bonjourName: nil
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
@@ -1,3 +1,3 @@
1
1
  module Apex
2
- VERSION = "0.0.2" unless defined?(Apex::VERSION)
2
+ VERSION = "0.0.3" unless defined?(Apex::VERSION)
3
3
  end
@@ -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.2
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-06-14 00:00:00.000000000 Z
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/main_spec.rb
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/main_spec.rb
83
+ - spec/unit/request_get_spec.rb
84
+ has_rdoc:
@@ -1,9 +0,0 @@
1
- describe "Application 'apex'" do
2
- before do
3
- @app = NSApplication.sharedApplication
4
- end
5
-
6
- it "has one window" do
7
- @app.windows.size.should == 1
8
- end
9
- end