gnarly 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.
- data/lib/gnarly/application.rb +61 -6
- data/lib/gnarly/base.rb +9 -5
- data/lib/gnarly/environment.rb +21 -0
- data/lib/gnarly/haml.rb +40 -0
- data/lib/gnarly/provides.rb +5 -15
- data/lib/gnarly/request.rb +10 -9
- data/lib/gnarly/status.rb +22 -0
- data/lib/gnarly/system.rb +35 -0
- data/lib/gnarly/understands.rb +21 -0
- data/lib/gnarly/url.rb +111 -14
- data/lib/gnarly.rb +1 -0
- metadata +7 -3
data/lib/gnarly/application.rb
CHANGED
@@ -1,28 +1,81 @@
|
|
1
|
-
require 'gnarly/provides.rb'
|
2
1
|
require 'gnarly/url.rb'
|
2
|
+
require 'gnarly/environment.rb'
|
3
3
|
|
4
4
|
module Gnarly
|
5
5
|
|
6
6
|
class Application
|
7
|
-
include
|
7
|
+
include Status
|
8
8
|
|
9
9
|
def initialize()
|
10
10
|
@urls = []
|
11
|
+
@environment = Environment.new self
|
12
|
+
end
|
13
|
+
|
14
|
+
def init(&block)
|
15
|
+
@environment.instance_exec &block
|
11
16
|
end
|
12
17
|
|
13
18
|
def url(url_mask, &block)
|
14
19
|
url = Url.new(url_mask)
|
15
|
-
url.instance_eval &block
|
20
|
+
url.instance_eval &block if block
|
16
21
|
@urls << url
|
22
|
+
url
|
23
|
+
end
|
24
|
+
|
25
|
+
def helper(helper)
|
26
|
+
(@helpers ||= []) << helper
|
17
27
|
end
|
18
28
|
|
19
|
-
def
|
20
|
-
|
29
|
+
def get(*args, &block)
|
30
|
+
m = args.shift
|
31
|
+
u = url m
|
32
|
+
u.get *args, &block
|
33
|
+
end
|
34
|
+
|
35
|
+
def put(*args, &block)
|
36
|
+
m = args.shift
|
37
|
+
u = url m
|
38
|
+
u.put *args, &block
|
39
|
+
end
|
40
|
+
|
41
|
+
def post(*args, &block)
|
42
|
+
m = args.shift
|
43
|
+
u = url m
|
44
|
+
u.post *args, &block
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete(*args, &block)
|
48
|
+
m = args.shift
|
49
|
+
u = url m
|
50
|
+
u.delete *args, &block
|
51
|
+
end
|
52
|
+
|
53
|
+
def call(state)
|
54
|
+
environment = @environment.dup
|
55
|
+
environment.extend *@helpers if @helpers
|
56
|
+
environment.state state
|
57
|
+
request = environment.request
|
21
58
|
path = request.path
|
22
59
|
if url = @urls.detect { |u| u.match? path }
|
23
60
|
@responder = url.responder request.method
|
24
61
|
if @responder
|
25
|
-
|
62
|
+
helpers = url.helpers
|
63
|
+
environment.extend *helpers if helpers
|
64
|
+
if before = url.before
|
65
|
+
environment.instance_exec *url.parameters, &before
|
66
|
+
end
|
67
|
+
keys = url.keys request.method
|
68
|
+
response = environment.instance_exec *url.parameters(*keys), &@responder
|
69
|
+
if after = url.after
|
70
|
+
environment.instance_exec *url.parameters, &after
|
71
|
+
end
|
72
|
+
unless response.is_a? Array and response.size == 3
|
73
|
+
name, line = @responder.source_location
|
74
|
+
msg = "Bad return type for block in #{name} line #{line}"
|
75
|
+
internal_server_error msg
|
76
|
+
else
|
77
|
+
response
|
78
|
+
end
|
26
79
|
else
|
27
80
|
method_not_allowed url.allow
|
28
81
|
end
|
@@ -31,6 +84,8 @@ module Gnarly
|
|
31
84
|
end
|
32
85
|
end
|
33
86
|
|
87
|
+
private
|
88
|
+
|
34
89
|
end
|
35
90
|
|
36
91
|
def self.application(&block)
|
data/lib/gnarly/base.rb
CHANGED
@@ -4,16 +4,20 @@ module Gnarly
|
|
4
4
|
|
5
5
|
module Base
|
6
6
|
|
7
|
-
def
|
8
|
-
if
|
9
|
-
@
|
7
|
+
def state(state=nil)
|
8
|
+
if state
|
9
|
+
@state = state
|
10
10
|
@request = nil
|
11
11
|
end
|
12
|
-
@
|
12
|
+
@state
|
13
13
|
end
|
14
14
|
|
15
15
|
def request()
|
16
|
-
@request ||= Request.new @
|
16
|
+
@request ||= Request.new @state
|
17
|
+
end
|
18
|
+
|
19
|
+
def logger()
|
20
|
+
@state["rack.logger"]
|
17
21
|
end
|
18
22
|
|
19
23
|
def body_charset(body)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'gnarly/provides.rb'
|
2
|
+
require 'gnarly/understands.rb'
|
3
|
+
|
4
|
+
module Gnarly
|
5
|
+
|
6
|
+
class Environment
|
7
|
+
include Provides
|
8
|
+
include Understands
|
9
|
+
|
10
|
+
def initialize(app)
|
11
|
+
@application = app
|
12
|
+
push_default_content_type "text/plain"
|
13
|
+
end
|
14
|
+
|
15
|
+
def application()
|
16
|
+
@application
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/gnarly/haml.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'haml'
|
2
|
+
|
3
|
+
module Gnarly
|
4
|
+
|
5
|
+
module Haml
|
6
|
+
|
7
|
+
def haml(name, &block)
|
8
|
+
root = application.haml_root
|
9
|
+
template = File.read "#{root}/#{name}.haml"
|
10
|
+
engine = ::Haml::Engine.new template
|
11
|
+
body = engine.render self
|
12
|
+
if block
|
13
|
+
push_default_content_type "text/html"
|
14
|
+
result = block.call body
|
15
|
+
pop_default_content_type
|
16
|
+
result
|
17
|
+
else
|
18
|
+
body
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class Application
|
25
|
+
|
26
|
+
def haml_root(haml_root=nil)
|
27
|
+
if haml_root
|
28
|
+
@haml_root = haml_root
|
29
|
+
else
|
30
|
+
@haml_root ||= "haml"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
class Environment
|
37
|
+
include Haml
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/lib/gnarly/provides.rb
CHANGED
@@ -11,25 +11,15 @@ module Gnarly
|
|
11
11
|
def provides(*mimes, &block)
|
12
12
|
mime = MIMEParse.best_match mimes, request.accept
|
13
13
|
if mime
|
14
|
+
push_default_content_type mime
|
14
15
|
response = block.call mime if block
|
15
|
-
|
16
|
-
|
17
|
-
unless headers.key? "Content-type"
|
18
|
-
charset = body_charset(body)
|
19
|
-
headers["Content-type"] =
|
20
|
-
charset ? "#{mime}; charset=#{charset}" : mime
|
21
|
-
end
|
22
|
-
response
|
23
|
-
else
|
24
|
-
name, line = @responder.source_location
|
25
|
-
msg = "Bad return type for block in #{filename} line #{line}"
|
26
|
-
internal_server_error msg
|
27
|
-
end
|
16
|
+
pop_default_content_type
|
17
|
+
response
|
28
18
|
else
|
29
19
|
not_acceptable
|
30
20
|
end
|
31
21
|
end
|
32
|
-
|
22
|
+
|
33
23
|
end
|
34
|
-
|
24
|
+
|
35
25
|
end
|
data/lib/gnarly/request.rb
CHANGED
@@ -3,22 +3,23 @@ require 'rack/utils'
|
|
3
3
|
module Gnarly
|
4
4
|
|
5
5
|
class Request
|
6
|
+
attr_reader :state
|
6
7
|
|
7
|
-
def initialize(
|
8
|
-
@
|
8
|
+
def initialize(state)
|
9
|
+
@state = state
|
9
10
|
parse_content_type
|
10
11
|
end
|
11
12
|
|
12
13
|
def path()
|
13
|
-
@path ||= @
|
14
|
+
@path ||= @state["PATH_INFO"]
|
14
15
|
end
|
15
16
|
|
16
17
|
def method()
|
17
|
-
@method ||= @
|
18
|
+
@method ||= @state["REQUEST_METHOD"].downcase.to_sym
|
18
19
|
end
|
19
20
|
|
20
21
|
def accept()
|
21
|
-
@accept ||= @
|
22
|
+
@accept ||= @state["HTTP_ACCEPT"]
|
22
23
|
end
|
23
24
|
|
24
25
|
def content_type()
|
@@ -31,7 +32,7 @@ module Gnarly
|
|
31
32
|
|
32
33
|
def body()
|
33
34
|
unless @body
|
34
|
-
input = @
|
35
|
+
input = @state["rack.input"]
|
35
36
|
@body = input.read
|
36
37
|
input.rewind
|
37
38
|
@body.force_encoding charset if charset
|
@@ -40,14 +41,14 @@ module Gnarly
|
|
40
41
|
end
|
41
42
|
|
42
43
|
def params()
|
43
|
-
@params ||= ::Rack::Utils.parse_query(@
|
44
|
+
@params ||= ::Rack::Utils.parse_query(@state["QUERY_STRING"])
|
44
45
|
end
|
45
46
|
|
46
47
|
private
|
47
48
|
|
48
49
|
def parse_content_type()
|
49
|
-
if header = @
|
50
|
-
header =~ /^([^;\s]+)(\s*;\s*charset=(\S+)\s*)
|
50
|
+
if header = @state["CONTENT_TYPE"]
|
51
|
+
header =~ /^([^;\s]+)(\s*;\s*charset=(\S+)\s*)?$/
|
51
52
|
@content_type = $1
|
52
53
|
@charset = $3
|
53
54
|
end
|
data/lib/gnarly/status.rb
CHANGED
@@ -3,11 +3,29 @@ module Gnarly
|
|
3
3
|
|
4
4
|
module Status
|
5
5
|
|
6
|
+
def push_default_content_type(mime)
|
7
|
+
(@default_content_types ||= []).push mime
|
8
|
+
end
|
9
|
+
|
10
|
+
def pop_default_content_type()
|
11
|
+
@default_content_types.pop if @default_content_types
|
12
|
+
end
|
13
|
+
|
14
|
+
def default_content_type()
|
15
|
+
@default_content_types.last if @default_content_types
|
16
|
+
end
|
17
|
+
|
6
18
|
def ok(body, mime=nil)
|
19
|
+
mime = default_content_type unless mime
|
7
20
|
headers = mime ? {"Content-type" => mime} : {}
|
8
21
|
[200, headers, [body]]
|
9
22
|
end
|
10
23
|
|
24
|
+
def created(location)
|
25
|
+
headers = {"Location" => location, "Content-type" => "text/plain"}
|
26
|
+
[201, headers, [""]]
|
27
|
+
end
|
28
|
+
|
11
29
|
def not_found(body="Not Found", mime="text/plain")
|
12
30
|
[404, {"Content-type" => mime}, [body]]
|
13
31
|
end
|
@@ -25,6 +43,10 @@ module Gnarly
|
|
25
43
|
[body]]
|
26
44
|
end
|
27
45
|
|
46
|
+
def unsupported_media_type(body="Unsupported Media Type", mime="text/plain")
|
47
|
+
[415, {"Content-type" => mime}, [body]]
|
48
|
+
end
|
49
|
+
|
28
50
|
def internal_server_error(body="Internal Server Error", mime="text/plain")
|
29
51
|
[500, {"Content-type" => mime}, [body]]
|
30
52
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
module Gnarly
|
3
|
+
|
4
|
+
class System
|
5
|
+
|
6
|
+
def initialize(*apps)
|
7
|
+
@apps = apps
|
8
|
+
end
|
9
|
+
|
10
|
+
def +(app)
|
11
|
+
@apps << app
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
response = nil
|
17
|
+
@apps.find do |app|
|
18
|
+
response = app.call(env)
|
19
|
+
status = response.first
|
20
|
+
status != 404 and status < 500
|
21
|
+
end
|
22
|
+
response
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
class Application
|
28
|
+
|
29
|
+
def +(other)
|
30
|
+
System.new self, other
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'gnarly/base.rb'
|
2
|
+
require 'gnarly/status.rb'
|
3
|
+
|
4
|
+
module Gnarly
|
5
|
+
|
6
|
+
module Understands
|
7
|
+
include Base
|
8
|
+
include Status
|
9
|
+
|
10
|
+
def understands(*mimes, &block)
|
11
|
+
mime = MIMEParse.best_match [request.content_type], mimes.join(",")
|
12
|
+
if mime
|
13
|
+
block.call mime if block
|
14
|
+
else
|
15
|
+
unsupported_media_type
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/gnarly/url.rb
CHANGED
@@ -4,50 +4,147 @@ module Gnarly
|
|
4
4
|
class Url
|
5
5
|
|
6
6
|
def initialize(url_mask)
|
7
|
-
|
7
|
+
case url_mask
|
8
|
+
when String
|
9
|
+
@url_mask = make_url_mask url_mask
|
10
|
+
when Regexp
|
11
|
+
@url_mask = url_mask
|
12
|
+
end
|
8
13
|
@responders = {}
|
14
|
+
@keys = {}
|
9
15
|
@allow = []
|
10
16
|
end
|
11
17
|
|
12
18
|
def match?(path)
|
13
|
-
@match = @url_mask.match path
|
19
|
+
@match = @url_mask.match path if @url_mask
|
14
20
|
@match != nil
|
15
21
|
end
|
16
22
|
|
17
|
-
def parameters()
|
18
|
-
|
19
|
-
|
20
|
-
|
23
|
+
def parameters(*keys)
|
24
|
+
if keys.empty?
|
25
|
+
a = @match.to_a
|
26
|
+
a.shift
|
27
|
+
if @types
|
28
|
+
(0..a.size - 1).collect do |i|
|
29
|
+
case @types[i]
|
30
|
+
when :integer
|
31
|
+
a[i].to_i
|
32
|
+
else
|
33
|
+
a[i]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
else
|
37
|
+
a
|
38
|
+
end
|
39
|
+
else
|
40
|
+
if @type_map
|
41
|
+
keys.collect do |key|
|
42
|
+
case @type_map[key.to_s]
|
43
|
+
when :integer
|
44
|
+
@match[key].to_i
|
45
|
+
else
|
46
|
+
@match[key]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
else
|
50
|
+
keys.collect do |key|
|
51
|
+
@match[key]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
21
55
|
end
|
22
56
|
|
23
57
|
def responder(method)
|
24
58
|
@responders[method]
|
25
59
|
end
|
26
60
|
|
61
|
+
def keys(method)
|
62
|
+
@keys[method]
|
63
|
+
end
|
64
|
+
|
27
65
|
def allow()
|
28
66
|
@allow.join " "
|
29
67
|
end
|
30
68
|
|
31
|
-
def
|
32
|
-
@
|
69
|
+
def helper(helper)
|
70
|
+
(@helpers ||= []) << helper
|
71
|
+
end
|
72
|
+
|
73
|
+
def helpers()
|
74
|
+
@helpers
|
75
|
+
end
|
76
|
+
|
77
|
+
def get(*keys, &block)
|
78
|
+
@responders[:get] = block
|
79
|
+
@keys[:get] = keys
|
33
80
|
@allow << "GET"
|
34
81
|
end
|
35
82
|
|
36
|
-
def put(&block)
|
37
|
-
@responders[
|
83
|
+
def put(*keys, &block)
|
84
|
+
@responders[:put] = block
|
85
|
+
@keys[:put] = keys
|
38
86
|
@allow << "PUT"
|
39
87
|
end
|
40
88
|
|
41
|
-
def post(&block)
|
42
|
-
@responders[
|
89
|
+
def post(*keys, &block)
|
90
|
+
@responders[:post] = block
|
91
|
+
@keys[:post] = keys
|
43
92
|
@allow << "POST"
|
44
93
|
end
|
45
94
|
|
46
|
-
def delete(&block)
|
47
|
-
@responders[
|
95
|
+
def delete(*keys, &block)
|
96
|
+
@responders[:delete] = block
|
97
|
+
@keys[:delete] = keys
|
48
98
|
@allow << "DELETE"
|
49
99
|
end
|
50
100
|
|
101
|
+
def before(&block)
|
102
|
+
if block
|
103
|
+
@before = block
|
104
|
+
else
|
105
|
+
@before
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def after(&block)
|
110
|
+
if block
|
111
|
+
@after = block
|
112
|
+
else
|
113
|
+
@after
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def make_url_mask(template)
|
118
|
+
types = []
|
119
|
+
type_map = {}
|
120
|
+
has_types = false
|
121
|
+
s = template.gsub(/\{([^\}]*)\}/) do
|
122
|
+
name, type = $1.split ":"
|
123
|
+
t = nil
|
124
|
+
p = case type
|
125
|
+
when "integer", "index"
|
126
|
+
has_types = true
|
127
|
+
t = :integer
|
128
|
+
types << t
|
129
|
+
'\d+'
|
130
|
+
else
|
131
|
+
types << nil
|
132
|
+
'[^/]+'
|
133
|
+
end
|
134
|
+
nc = ""
|
135
|
+
if name and name != ""
|
136
|
+
nc = "?<#{name}>"
|
137
|
+
type_map[name] = t
|
138
|
+
end
|
139
|
+
"(#{nc}#{p})"
|
140
|
+
end
|
141
|
+
if has_types
|
142
|
+
@types = types
|
143
|
+
@type_map = type_map
|
144
|
+
end
|
145
|
+
Regexp.new "^#{s}$"
|
146
|
+
end
|
147
|
+
|
51
148
|
end
|
52
149
|
|
53
150
|
end
|
data/lib/gnarly.rb
CHANGED
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 3
|
9
|
+
version: 0.0.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Kim Dalsgaard
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-03-08 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -29,10 +29,14 @@ extra_rdoc_files: []
|
|
29
29
|
files:
|
30
30
|
- lib/gnarly/application.rb
|
31
31
|
- lib/gnarly/base.rb
|
32
|
+
- lib/gnarly/environment.rb
|
33
|
+
- lib/gnarly/haml.rb
|
32
34
|
- lib/gnarly/mimeparse.rb
|
33
35
|
- lib/gnarly/provides.rb
|
34
36
|
- lib/gnarly/request.rb
|
35
37
|
- lib/gnarly/status.rb
|
38
|
+
- lib/gnarly/system.rb
|
39
|
+
- lib/gnarly/understands.rb
|
36
40
|
- lib/gnarly/url.rb
|
37
41
|
- lib/gnarly/uuid.rb
|
38
42
|
- lib/gnarly.rb
|