renee-core 0.0.1
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/README.md +242 -0
- data/Rakefile +8 -0
- data/ideal.rb +49 -0
- data/lib/renee-core/application/rack_interaction.rb +39 -0
- data/lib/renee-core/application/request_context.rb +22 -0
- data/lib/renee-core/application/responding.rb +122 -0
- data/lib/renee-core/application/routing.rb +245 -0
- data/lib/renee-core/application.rb +28 -0
- data/lib/renee-core/response.rb +78 -0
- data/lib/renee-core/settings.rb +34 -0
- data/lib/renee-core/url_generation.rb +109 -0
- data/lib/renee-core/version.rb +6 -0
- data/lib/renee-core.rb +64 -0
- data/renee-core.gemspec +26 -0
- data/test/responding_test.rb +128 -0
- data/test/routing_test.rb +422 -0
- data/test/test_helper.rb +4 -0
- data/test/url_generation_test.rb +66 -0
- metadata +169 -0
@@ -0,0 +1,245 @@
|
|
1
|
+
class Renee
|
2
|
+
class Core
|
3
|
+
class Application
|
4
|
+
# Collection of useful methods for routing within a {Renee::Core} app.
|
5
|
+
module Routing
|
6
|
+
# Match a path to respond to.
|
7
|
+
#
|
8
|
+
# @param [String] p
|
9
|
+
# path to match.
|
10
|
+
# @param [Proc] blk
|
11
|
+
# block to yield
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# path('/') { ... } #=> '/'
|
15
|
+
# path('test') { ... } #=> '/test'
|
16
|
+
#
|
17
|
+
# path 'foo' do
|
18
|
+
# path('bar') { ... } #=> '/foo/bar'
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
def path(p, &blk)
|
23
|
+
p = p[1, p.size] if p[0] == ?/
|
24
|
+
part(/^\/#{Regexp.quote(p)}(\/?$)?/, &blk)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Like #path, but requires the entire path to be consumed.
|
28
|
+
# @see #path
|
29
|
+
def whole_path(p, &blk)
|
30
|
+
path(p) { complete(&blk) }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Like #path, but doesn't automatically match trailing-slashes.
|
34
|
+
# @see #path
|
35
|
+
def exact_path(p, &blk)
|
36
|
+
p = p[1, part.size] if p[0] == ?/
|
37
|
+
part(/^\/#{Regexp.quote(p)}/, &blk)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Like #path, doesn't look for leading slashes.
|
41
|
+
def part(p)
|
42
|
+
p = /\/?#{Regexp.quote(p)}/ if p.is_a?(String)
|
43
|
+
if match = env['PATH_INFO'][p]
|
44
|
+
with_path_part(match) { yield }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Match parts off the path as variables.
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# path '/' do
|
52
|
+
# variable { |id| halt [200, {}, id }
|
53
|
+
# end
|
54
|
+
# GET /hey #=> [200, {}, 'hey']
|
55
|
+
#
|
56
|
+
# path '/test' do
|
57
|
+
# variable { |foo, bar| halt [200, {}, "#{foo}-#{bar}"] }
|
58
|
+
# end
|
59
|
+
# GET /test/hey/there #=> [200, {}, 'hey-there']
|
60
|
+
#
|
61
|
+
# @api public
|
62
|
+
def variable(*args, &blk)
|
63
|
+
args << {} unless args.last.is_a?(Hash)
|
64
|
+
args.last[:prepend] = '/'
|
65
|
+
partial_variable(*args, &blk)
|
66
|
+
end
|
67
|
+
alias_method :var, :variable
|
68
|
+
|
69
|
+
# Match parts off the path as variables without a leading slash.
|
70
|
+
# @see #variable
|
71
|
+
# @api public
|
72
|
+
def partial_variable(*args, &blk)
|
73
|
+
opts = args.last.is_a?(Hash) ? args.pop : nil
|
74
|
+
type = args.first || opts && opts[:type]
|
75
|
+
prepend = opts && opts[:prepend] || ''
|
76
|
+
if type == Integer
|
77
|
+
complex_variable(/#{Regexp.quote(prepend)}(\d+)/, proc{|v| Integer(v)}, &blk)
|
78
|
+
else case type
|
79
|
+
when nil
|
80
|
+
complex_variable(/#{Regexp.quote(prepend)}([^\/]+)/, &blk)
|
81
|
+
when Regexp
|
82
|
+
complex_variable(/#{Regexp.quote(prepend)}(#{type.to_s})/, &blk)
|
83
|
+
else
|
84
|
+
raise "Unexpected variable type #{type.inspect}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
alias_method :part_var, :partial_variable
|
89
|
+
|
90
|
+
# Match an extension.
|
91
|
+
#
|
92
|
+
# @example
|
93
|
+
# extension('html') { |path| halt [200, {}, path] }
|
94
|
+
#
|
95
|
+
# @api public
|
96
|
+
def extension(ext)
|
97
|
+
if detected_extension && match = detected_extension[ext]
|
98
|
+
if match == detected_extension
|
99
|
+
(ext_match = env['PATH_INFO'][/\/?\.#{match}/]) ?
|
100
|
+
with_path_part(ext_match) { yield } : yield
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
alias_method :ext, :extension
|
105
|
+
|
106
|
+
# Match no extension.
|
107
|
+
#
|
108
|
+
# @example
|
109
|
+
# no_extension { |path| halt [200, {}, path] }
|
110
|
+
#
|
111
|
+
# @api public
|
112
|
+
def no_extension
|
113
|
+
yield if detected_extension.nil?
|
114
|
+
end
|
115
|
+
|
116
|
+
# Match any remaining path.
|
117
|
+
#
|
118
|
+
# @example
|
119
|
+
# remainder { |path| halt [200, {}, path] }
|
120
|
+
#
|
121
|
+
# @api public
|
122
|
+
def remainder
|
123
|
+
with_path_part(env['PATH_INFO']) { |var| yield var }
|
124
|
+
end
|
125
|
+
alias_method :catchall, :remainder
|
126
|
+
|
127
|
+
# Respond to a GET request and yield the block.
|
128
|
+
#
|
129
|
+
# @example
|
130
|
+
# get { halt [200, {}, "hello world"] }
|
131
|
+
#
|
132
|
+
# @api public
|
133
|
+
def get(path = nil)
|
134
|
+
request_method('GET', path) { yield }
|
135
|
+
end
|
136
|
+
|
137
|
+
# Respond to a POST request and yield the block.
|
138
|
+
#
|
139
|
+
# @example
|
140
|
+
# post { halt [200, {}, "hello world"] }
|
141
|
+
#
|
142
|
+
# @api public
|
143
|
+
def post(path = nil)
|
144
|
+
request_method('POST', path) { yield }
|
145
|
+
end
|
146
|
+
|
147
|
+
# Respond to a PUT request and yield the block.
|
148
|
+
#
|
149
|
+
# @example
|
150
|
+
# put { halt [200, {}, "hello world"] }
|
151
|
+
#
|
152
|
+
# @api public
|
153
|
+
def put(path = nil)
|
154
|
+
request_method('PUT', path) { yield }
|
155
|
+
end
|
156
|
+
|
157
|
+
# Respond to a DELETE request and yield the block.
|
158
|
+
#
|
159
|
+
# @example
|
160
|
+
# delete { halt [200, {}, "hello world"] }
|
161
|
+
#
|
162
|
+
# @api public
|
163
|
+
def delete(path = nil)
|
164
|
+
request_method('DELETE', path) { yield }
|
165
|
+
end
|
166
|
+
|
167
|
+
# Match only when the path has been completely consumed.
|
168
|
+
#
|
169
|
+
# @example
|
170
|
+
# delete { halt [200, {}, "hello world"] }
|
171
|
+
#
|
172
|
+
# @api public
|
173
|
+
def complete
|
174
|
+
with_path_part(env['PATH_INFO']) { yield } if env['PATH_INFO'] == '' || is_index_request
|
175
|
+
end
|
176
|
+
|
177
|
+
# Match variables within the query string.
|
178
|
+
#
|
179
|
+
# @param [Array, Hash] q
|
180
|
+
# Either an array or hash of things to match query string variables. If given
|
181
|
+
# an array, if you pass the values for each key as parameters to the block given.
|
182
|
+
# If given a hash, then every value must be able to #=== match each value in the query
|
183
|
+
# parameters for each key in the hash.
|
184
|
+
#
|
185
|
+
# @example
|
186
|
+
# query(:key => 'value') { halt [200, {}, "hello world"] }
|
187
|
+
#
|
188
|
+
# @example
|
189
|
+
# query(:key) { |val| halt [200, {}, "key is #{val}"] }
|
190
|
+
#
|
191
|
+
# @api public
|
192
|
+
def query(q, &blk)
|
193
|
+
case q
|
194
|
+
when Hash then q.any? {|k,v| !(v === request[k.to_s]) } ? return : yield
|
195
|
+
when Array then yield *q.map{|qk| request[qk.to_s] or return }
|
196
|
+
else query([q], &blk)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Yield block if the query string matches.
|
201
|
+
#
|
202
|
+
# @param [String] qs
|
203
|
+
# The query string to match.
|
204
|
+
#
|
205
|
+
# @example
|
206
|
+
# path 'test' do
|
207
|
+
# query_string 'foo=bar' do
|
208
|
+
# halt [200, {}, 'matched']
|
209
|
+
# end
|
210
|
+
# end
|
211
|
+
# GET /test?foo=bar #=> 'matched'
|
212
|
+
#
|
213
|
+
# @api public
|
214
|
+
def query_string(qs)
|
215
|
+
yield if qs === env['QUERY_STRING']
|
216
|
+
end
|
217
|
+
|
218
|
+
private
|
219
|
+
def complex_variable(matcher = nil, transformer = nil, &blk)
|
220
|
+
warn "variable currently isn't taking any parameters" unless blk.arity > 0
|
221
|
+
if var_value = /^#{(matcher ? matcher.to_s : '\/([^\/]+)') * blk.arity}/.match(env['PATH_INFO'])
|
222
|
+
vars = var_value.to_a
|
223
|
+
with_path_part(vars.shift) { blk.call *vars.map{|v| transformer ? transformer[v[0, v.size]] : v[0, v.size]} }
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def with_path_part(part)
|
228
|
+
old_path_info = env['PATH_INFO']
|
229
|
+
old_script_name = env['SCRIPT_NAME']
|
230
|
+
old_path_info[part.size, old_path_info.size - part.size]
|
231
|
+
script_part, remaining_part = old_path_info[0, part.size], old_path_info[part.size, old_path_info.size]
|
232
|
+
env['SCRIPT_NAME'] += script_part
|
233
|
+
env['PATH_INFO'] = remaining_part
|
234
|
+
yield script_part
|
235
|
+
env['PATH_INFO'] = old_path_info
|
236
|
+
env['SCRIPT_NAME'] = old_script_name
|
237
|
+
end
|
238
|
+
|
239
|
+
def request_method(method, path = nil)
|
240
|
+
path ? whole_path(path) { yield } : complete { yield } if env['REQUEST_METHOD'] == method
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/application/request_context")
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + "/application/routing")
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/application/responding")
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + "/application/rack_interaction")
|
5
|
+
|
6
|
+
class Renee
|
7
|
+
class Core
|
8
|
+
# This is the main class used to do the respond to requests. {Routing} provides route helpers.
|
9
|
+
# {RequestContext} adds the RequestContext#call method to respond to Rack applications.
|
10
|
+
# {Responding} defines the method Responding#halt which stops processing within a {Renee::Application}.
|
11
|
+
# It also has methods to interpret arguments to #halt and redirection response helpers.
|
12
|
+
# {RackInteraction} adds methods for interacting with Rack.
|
13
|
+
class Application
|
14
|
+
include RequestContext
|
15
|
+
include Routing
|
16
|
+
include Responding
|
17
|
+
include RackInteraction
|
18
|
+
|
19
|
+
attr_reader :application_block, :settings
|
20
|
+
|
21
|
+
# @param [Proc] application_block The block that will be #instance_eval'd on each invocation to #call
|
22
|
+
def initialize(settings, &application_block)
|
23
|
+
@settings = settings
|
24
|
+
@application_block = application_block
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
class Renee
|
2
|
+
class Core
|
3
|
+
# The response object for a Renee request. Inherits from the `Rack#Response` object.
|
4
|
+
class Response < Rack::Response
|
5
|
+
# Augment body to allow strings.
|
6
|
+
#
|
7
|
+
# @param [String] The contents for the response.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# res.body = "Hello"
|
11
|
+
#
|
12
|
+
# @api semipublic
|
13
|
+
def body=(value)
|
14
|
+
value = value.body while Rack::Response === value
|
15
|
+
@body = String === value ? [value.to_str] : value
|
16
|
+
end
|
17
|
+
|
18
|
+
# Alias status and body methods to allow redefinition
|
19
|
+
alias :status_attr :status
|
20
|
+
alias :status_attr= :status=
|
21
|
+
alias :body_attr :body
|
22
|
+
alias :body_attr= :body=
|
23
|
+
|
24
|
+
# Get or set the status of the response.
|
25
|
+
#
|
26
|
+
# @param [String] val The status code to return.
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# res.status 400
|
30
|
+
# res.status => 400
|
31
|
+
#
|
32
|
+
# @api public
|
33
|
+
def status(val=nil)
|
34
|
+
val ? self.status_attr = val : self.status_attr
|
35
|
+
end
|
36
|
+
|
37
|
+
# Get or set the body of the response.
|
38
|
+
#
|
39
|
+
# @param [String] val The contents to return.
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# res.body "hello"
|
43
|
+
# res.body => "hello"
|
44
|
+
#
|
45
|
+
# @api public
|
46
|
+
def body(val=nil)
|
47
|
+
val ? self.body_attr = val : self.body_attr
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get or set the headers of the response.
|
51
|
+
#
|
52
|
+
# @param [Hash] attrs The contents to return.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# res.headers :foo => "bar"
|
56
|
+
# res.headers => { :foo => "bar" }
|
57
|
+
#
|
58
|
+
# @api public
|
59
|
+
def headers(attrs={})
|
60
|
+
attrs ? attrs.each { |k, v| self[k.to_s] = v } : self.header
|
61
|
+
end
|
62
|
+
|
63
|
+
# Finishs the response based on the accumulated options.
|
64
|
+
# Calculates the size of the body content length and removes headers for 1xx status codes.
|
65
|
+
def finish
|
66
|
+
if status.to_i / 100 == 1
|
67
|
+
headers.delete "Content-Length"
|
68
|
+
headers.delete "Content-Type"
|
69
|
+
elsif Array === body and not [204, 304].include?(status.to_i)
|
70
|
+
headers["Content-Length"] = body.inject(0) { |l, p| l + Rack::Utils.bytesize(p) }.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
status, headers, result = super
|
74
|
+
[status, headers, result]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Renee
|
2
|
+
class Core
|
3
|
+
##
|
4
|
+
# Stores configuration settings for a particular Renee application.
|
5
|
+
# Powers the Renee setup block which is instance eval'ed into this object.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# Renee::Core.new { ... }.setup { views_path "./views" }
|
9
|
+
#
|
10
|
+
class Settings
|
11
|
+
attr_reader :includes
|
12
|
+
def initialize
|
13
|
+
@includes = []
|
14
|
+
end
|
15
|
+
|
16
|
+
# Get or sets the views_path for an application.
|
17
|
+
#
|
18
|
+
# @param [String] path The path to the view files.
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# views_path("./views") => nil
|
22
|
+
# views_path => "./views"
|
23
|
+
#
|
24
|
+
# @api public
|
25
|
+
def views_path(path = nil)
|
26
|
+
path ? @views_path = path : @views_path
|
27
|
+
end
|
28
|
+
|
29
|
+
def include(mod)
|
30
|
+
includes << mod
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
class Renee
|
4
|
+
class Core
|
5
|
+
# URL generator for creating paths and URLs within your application.
|
6
|
+
module URLGeneration
|
7
|
+
|
8
|
+
# Registers new paths for generation.
|
9
|
+
# @param [Symbol] name The name of the path
|
10
|
+
# @param [String] pattern The pattern used for generation.
|
11
|
+
# @param [Hash, nil] defaults Any default values used for generation.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# renee.register(:path, "/my/:var/path")
|
15
|
+
# renee.path(:path, 123) # => "/my/123/path"
|
16
|
+
# renee.path(:path, :var => 'hey you') # => "/my/hey%20you/path"
|
17
|
+
def register(name, pattern, defaults = nil)
|
18
|
+
url_generators[name] = Generator.new("#{@generation_prefix}#{pattern}", defaults_for_generation(defaults))
|
19
|
+
end
|
20
|
+
|
21
|
+
# Allows the creation of generation contexts.
|
22
|
+
# @param [String] prefix The prefix to add to subsequent calls to #register.
|
23
|
+
# @param [Hash, nil] defaults The defaults to add to subsequent calls to #register.
|
24
|
+
# @see #register
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# renee.prefix("/prefix") {
|
28
|
+
# renee.register(:prefix_path, "/path") # would register /prefix/path
|
29
|
+
# }
|
30
|
+
def prefix(prefix, defaults = nil, &blk)
|
31
|
+
generator = self
|
32
|
+
subgenerator = Class.new {
|
33
|
+
include URLGeneration
|
34
|
+
define_method(:url_generators) { generator.send(:url_generators) }
|
35
|
+
}.new
|
36
|
+
subgenerator.instance_variable_set(:@generation_prefix, "#{@generation_prefix}#{prefix}")
|
37
|
+
subgenerator.instance_variable_set(:@generation_defaults, defaults_for_generation(defaults))
|
38
|
+
if block_given?
|
39
|
+
old_prefix, old_defaults = @generation_prefix, @generation_defaults
|
40
|
+
@generation_prefix, @generation_defaults = "#{@generation_prefix}#{prefix}", defaults_for_generation(defaults)
|
41
|
+
subgenerator.instance_eval(&blk)
|
42
|
+
@generation_prefix, @generation_defaults = old_prefix, old_defaults
|
43
|
+
end
|
44
|
+
subgenerator
|
45
|
+
end
|
46
|
+
|
47
|
+
# Generates a path for a given name.
|
48
|
+
# @param [Symbol] name The name of the path
|
49
|
+
# @param [Object] args The values used to generate the path. Can be named with using :name => "value" or supplied
|
50
|
+
# in the order for which the variables were decalared in #register.
|
51
|
+
#
|
52
|
+
# @see #register
|
53
|
+
def path(name, *args)
|
54
|
+
generator = url_generators[name]
|
55
|
+
generator ? generator.path(*args) : raise("Generator for #{name} doesn't exist")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Generates a url for a given name.
|
59
|
+
# @param (see #path)
|
60
|
+
# @see #path
|
61
|
+
def url(name, *args)
|
62
|
+
generator = url_generators[name]
|
63
|
+
generator ? generator.url(*args) : raise("Generator for #{name} doesn't exist")
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def url_generators
|
68
|
+
@url_generators ||= {}
|
69
|
+
end
|
70
|
+
|
71
|
+
def defaults_for_generation(defaults)
|
72
|
+
@generation_defaults && defaults ? @generation_defaults.merge(defaults) : (defaults || @generation_defaults)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Manages generating paths and urls for a given name.
|
76
|
+
# @private
|
77
|
+
class Generator
|
78
|
+
attr_reader :defaults
|
79
|
+
|
80
|
+
def initialize(template, defaults = nil)
|
81
|
+
@defaults = defaults
|
82
|
+
parsed_template = URI.parse(template)
|
83
|
+
@host = parsed_template.host
|
84
|
+
@template = parsed_template.path
|
85
|
+
@scheme = parsed_template.scheme
|
86
|
+
port = parsed_template.port
|
87
|
+
if !port.nil? and (@scheme.nil? or @scheme == "http" && port != '80' or @scheme == "https" && port != '443')
|
88
|
+
@port_part = ":#{port}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def path(*args)
|
93
|
+
opts = args.last.is_a?(Hash) ? args.pop : nil
|
94
|
+
opts = opts ? defaults.merge(opts) : defaults.dup if defaults
|
95
|
+
path = @template.gsub(/:([a-zA-Z0-9_]+)/) { |name|
|
96
|
+
name = name[1, name.size - 1].to_sym
|
97
|
+
(opts && opts.delete(name)) || (defaults && defaults[name]) || args.shift || raise("variable #{name.inspect} not found")
|
98
|
+
}
|
99
|
+
URI.encode(opts.nil? || opts.empty? ? path : "#{path}?#{Rack::Utils.build_query(opts)}")
|
100
|
+
end
|
101
|
+
|
102
|
+
def url(*args)
|
103
|
+
raise "This URL cannot be generated as no host has been defined." if @host.nil?
|
104
|
+
"#{@scheme}://#{@host}#{@port_part}#{path(*args)}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/renee-core.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'renee-core/version'
|
3
|
+
require 'renee-core/settings'
|
4
|
+
require 'renee-core/response'
|
5
|
+
require 'renee-core/application'
|
6
|
+
require 'renee-core/url_generation'
|
7
|
+
|
8
|
+
# Renee top-level constant
|
9
|
+
class Renee
|
10
|
+
# The top-level class for creating core application.
|
11
|
+
# For convience you can also used a method named #Renee
|
12
|
+
# for decalaring new instances.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# Renee::Core.new { path('/hello') { halt :ok } }
|
16
|
+
#
|
17
|
+
class Core
|
18
|
+
include URLGeneration
|
19
|
+
|
20
|
+
attr_reader :application_block, :settings
|
21
|
+
|
22
|
+
# @param [Proc] application_block The block of code that will be executed on each invocation of call #call.
|
23
|
+
# Each time #call is called, a new instance of {Renee::Core::Application} will
|
24
|
+
# be created. The block given will be #instance_eval 'd within
|
25
|
+
# the context of that new instance.
|
26
|
+
#
|
27
|
+
def initialize(&application_block)
|
28
|
+
@application_block = application_block
|
29
|
+
@settings = Settings.new
|
30
|
+
end
|
31
|
+
|
32
|
+
# This is a rack-compliant `Rack#call`.
|
33
|
+
#
|
34
|
+
# @param [Hash] env The environment hash.
|
35
|
+
#
|
36
|
+
# @return [Array] A rack compliant return.
|
37
|
+
#
|
38
|
+
# @see http://rack.rubyforge.org/doc/SPEC.html
|
39
|
+
#
|
40
|
+
def call(env)
|
41
|
+
Application.new(settings, &application_block).call(env)
|
42
|
+
end
|
43
|
+
alias_method :[], :call
|
44
|
+
|
45
|
+
##
|
46
|
+
# Configure settings for your Renee application. Accepts a settings file path
|
47
|
+
# or a block containing the configuration settings.
|
48
|
+
#
|
49
|
+
# @example
|
50
|
+
# Renee::Core.new { ... }.setup { views_path "./views" }
|
51
|
+
#
|
52
|
+
# @api public
|
53
|
+
def setup(path = nil, &blk)
|
54
|
+
raise "Must be either path or blk to configure settings" if path && blk
|
55
|
+
case path
|
56
|
+
when nil then settings.instance_eval(&blk)
|
57
|
+
when Settings then @settings = path
|
58
|
+
when String then File.exist?(path) ? settings.instance_eval(File.read(path), path, 1) : raise("The settings file #{path} does not exist")
|
59
|
+
else raise "Could not setup with #{path.inspect}"
|
60
|
+
end
|
61
|
+
self
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/renee-core.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "renee-core/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "renee-core"
|
7
|
+
s.version = Renee::Core::VERSION
|
8
|
+
s.authors = ["Josh Hull", "Nathan Esquenazi", "Arthur Chiu"]
|
9
|
+
s.email = ["joshbuddy@gmail.com", "nesquena@gmail.com", "mr.arthur.chiu@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{The super-friendly rack helpers.}
|
12
|
+
s.description = %q{The super-friendly rack helpers.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "renee"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_runtime_dependency 'rack', "~> 1.3.0"
|
22
|
+
s.add_development_dependency 'minitest', "~> 2.6.1"
|
23
|
+
s.add_development_dependency 'bundler', "~> 1.0.10"
|
24
|
+
s.add_development_dependency "rack-test", ">= 0.5.0"
|
25
|
+
s.add_development_dependency "rake", "0.8.7"
|
26
|
+
end
|