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 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