pakyow-core 0.7.2 → 0.8rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/pakyow-core/bin/pakyow +7 -6
- data/pakyow-core/lib/commands/USAGE +2 -1
- data/pakyow-core/lib/commands/console.rb +1 -1
- data/pakyow-core/lib/commands/server.rb +1 -1
- data/pakyow-core/lib/core/application.rb +129 -404
- data/pakyow-core/lib/core/base.rb +16 -4
- data/pakyow-core/lib/core/configuration/app.rb +6 -2
- data/pakyow-core/lib/core/configuration/server.rb +6 -1
- data/pakyow-core/lib/core/fn_context.rb +5 -0
- data/pakyow-core/lib/core/helpers.rb +16 -0
- data/pakyow-core/lib/core/loader.rb +1 -2
- data/pakyow-core/lib/core/log.rb +13 -9
- data/pakyow-core/lib/core/middleware/logger.rb +37 -0
- data/pakyow-core/lib/core/middleware/not_found.rb +40 -0
- data/pakyow-core/lib/core/middleware/presenter.rb +25 -0
- data/pakyow-core/lib/core/middleware/reloader.rb +14 -0
- data/pakyow-core/lib/core/middleware/router.rb +33 -0
- data/pakyow-core/lib/core/middleware/setup.rb +15 -0
- data/pakyow-core/lib/core/middleware/static.rb +27 -0
- data/pakyow-core/lib/core/presenter_base.rb +4 -0
- data/pakyow-core/lib/core/request.rb +43 -15
- data/pakyow-core/lib/core/response.rb +6 -0
- data/pakyow-core/lib/core/route_lookup.rb +37 -0
- data/pakyow-core/lib/core/route_set.rb +260 -0
- data/pakyow-core/lib/core/route_template.rb +77 -0
- data/pakyow-core/lib/core/route_template_defaults.rb +29 -0
- data/pakyow-core/lib/core/router.rb +156 -0
- data/pakyow-core/lib/generators/pakyow/app/app_generator.rb +12 -2
- data/pakyow-core/lib/generators/pakyow/app/templates/app.rb +12 -0
- data/pakyow-core/lib/generators/pakyow/app/templates/config.ru +1 -1
- data/pakyow-core/lib/generators/pakyow/app/templates/rakefile +1 -1
- data/pakyow-core/lib/generators/pakyow/app/templates/{app/views → views}/main.html +0 -0
- data/pakyow-core/lib/generators/pakyow/app/templates/{app/views → views}/pakyow.html +1 -1
- data/pakyow-core/lib/utils/string.rb +11 -10
- metadata +61 -71
- data/pakyow-core/lib/core/logger.rb +0 -33
- data/pakyow-core/lib/core/reloader.rb +0 -12
- data/pakyow-core/lib/core/route_store.rb +0 -220
- data/pakyow-core/lib/core/static.rb +0 -25
- data/pakyow-core/lib/generators/pakyow/app/templates/app/lib/application_controller.rb +0 -6
- data/pakyow-core/lib/generators/pakyow/app/templates/config/application.rb +0 -18
- data/pakyow-core/lib/generators/pakyow/app/templates/logs/requests.log +0 -0
@@ -0,0 +1,260 @@
|
|
1
|
+
module Pakyow
|
2
|
+
class RouteSet
|
3
|
+
def initialize
|
4
|
+
@routes = {:get => [], :post => [], :put => [], :delete => []}
|
5
|
+
|
6
|
+
@routes_by_name = {}
|
7
|
+
@grouped_routes_by_name = {}
|
8
|
+
|
9
|
+
@fns = {}
|
10
|
+
@groups = {}
|
11
|
+
|
12
|
+
@templates = {}
|
13
|
+
|
14
|
+
@handlers = []
|
15
|
+
|
16
|
+
@scope = {:name => nil, :path => '/', :hooks => {:before => [], :after => []}}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Creates or retreives a named route function. When retrieving,
|
20
|
+
#
|
21
|
+
def fn(name, &block)
|
22
|
+
@fns[name] = block and return if block
|
23
|
+
|
24
|
+
#TODO rewrite to not return array
|
25
|
+
[@fns[name]]
|
26
|
+
end
|
27
|
+
|
28
|
+
def default(*args, &block)
|
29
|
+
self.register_route(:get, '/', *args, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def get(*args, &block)
|
33
|
+
self.register_route(:get, *args, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def put(*args, &block)
|
37
|
+
self.register_route(:put, *args, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def post(*args, &block)
|
41
|
+
self.register_route(:post, *args, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def delete(*args, &block)
|
45
|
+
self.register_route(:delete, *args, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns a lambda that routes request to a controller/action.
|
49
|
+
#TODO move to RouteHelpers
|
50
|
+
def call(controller, action)
|
51
|
+
lambda {
|
52
|
+
controller = Object.const_get(controller)
|
53
|
+
action ||= Configuration::Base.app.default_action
|
54
|
+
|
55
|
+
instance = controller.new
|
56
|
+
request.controller = instance
|
57
|
+
request.action = action
|
58
|
+
|
59
|
+
instance.send(action)
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
# Creates a handler.
|
64
|
+
#
|
65
|
+
def handler(name, *args, &block)
|
66
|
+
code, fn = args
|
67
|
+
|
68
|
+
fn = code and code = nil if code.is_a?(Proc)
|
69
|
+
fn = block if block_given?
|
70
|
+
|
71
|
+
@handlers << [name, code, [fn]]
|
72
|
+
end
|
73
|
+
|
74
|
+
def group(name, *args, &block)
|
75
|
+
# deep clone existing hooks to reset at the close of this group
|
76
|
+
original_hooks = Marshal.load(Marshal.dump(@scope[:hooks]))
|
77
|
+
|
78
|
+
@scope[:hooks] = self.merge_hooks(@scope[:hooks], args[0]) if @scope[:hooks] && args[0]
|
79
|
+
|
80
|
+
@scope[:name] = name
|
81
|
+
@groups[name] = []
|
82
|
+
@grouped_routes_by_name[name] = {}
|
83
|
+
|
84
|
+
self.instance_exec(&block)
|
85
|
+
@scope[:name] = nil
|
86
|
+
|
87
|
+
@scope[:hooks] = original_hooks
|
88
|
+
end
|
89
|
+
|
90
|
+
def namespace(path, *args, &block)
|
91
|
+
name, hooks = args
|
92
|
+
hooks = name if name.is_a?(Hash)
|
93
|
+
|
94
|
+
original_path = @scope[:path]
|
95
|
+
@scope[:path] = File.join(@scope[:path], path)
|
96
|
+
|
97
|
+
self.group(name, hooks || {}, &block)
|
98
|
+
@scope[:path] = original_path
|
99
|
+
end
|
100
|
+
|
101
|
+
def template(name, &block)
|
102
|
+
@templates[name] = block
|
103
|
+
end
|
104
|
+
|
105
|
+
def expand(t_name, g_name, path = nil, data = nil, &block)
|
106
|
+
data = path and path = nil if path.is_a?(Hash)
|
107
|
+
|
108
|
+
# evaluate block in context of some class that implements
|
109
|
+
# method_missing to store map of functions
|
110
|
+
# (e.g. index, show)
|
111
|
+
t = RouteTemplate.new(block, g_name, path, self)
|
112
|
+
|
113
|
+
# evaluate template in same context, where func looks up funcs
|
114
|
+
# from map and extends get (and others) to add proper names
|
115
|
+
t.expand(@templates[t_name], data)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns a route tuple:
|
119
|
+
# [regex, vars, name, fns, path]
|
120
|
+
#
|
121
|
+
def match(path, method)
|
122
|
+
path = StringUtils.normalize_path(path)
|
123
|
+
|
124
|
+
@routes[method.to_sym].each{|r|
|
125
|
+
case r[0]
|
126
|
+
when Regexp
|
127
|
+
if data = r[0].match(path)
|
128
|
+
return r, data
|
129
|
+
end
|
130
|
+
when String
|
131
|
+
if r[0] == path
|
132
|
+
return r, nil
|
133
|
+
end
|
134
|
+
end
|
135
|
+
}
|
136
|
+
|
137
|
+
nil
|
138
|
+
end
|
139
|
+
|
140
|
+
def handle(name_or_code)
|
141
|
+
@handlers.each{ |h|
|
142
|
+
return h if h[0] == name_or_code || h[1] == name_or_code
|
143
|
+
}
|
144
|
+
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
|
148
|
+
# Name based route lookup
|
149
|
+
def route(name, group = nil)
|
150
|
+
return @routes_by_name[name] unless group
|
151
|
+
|
152
|
+
if grouped_routes = @grouped_routes_by_name[group]
|
153
|
+
grouped_routes[name]
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
protected
|
158
|
+
|
159
|
+
def merge_hooks(h1, h2)
|
160
|
+
# normalize
|
161
|
+
h1[:before] ||= []
|
162
|
+
h1[:after] ||= []
|
163
|
+
h1[:around] ||= []
|
164
|
+
h2[:before] ||= []
|
165
|
+
h2[:after] ||= []
|
166
|
+
h2[:around] ||= []
|
167
|
+
|
168
|
+
# merge
|
169
|
+
h1[:before].concat(h2[:before])
|
170
|
+
h1[:after].concat(h2[:after])
|
171
|
+
h1[:around].concat(h2[:around])
|
172
|
+
h1
|
173
|
+
end
|
174
|
+
|
175
|
+
def register_route(method, path, *args, &block)
|
176
|
+
name, fns, hooks = self.parse_route_args(args)
|
177
|
+
|
178
|
+
fns ||= []
|
179
|
+
# add passed block to fns
|
180
|
+
fns << block if block_given?
|
181
|
+
|
182
|
+
hooks = self.merge_hooks(hooks || {}, @scope[:hooks])
|
183
|
+
|
184
|
+
# build the final list of fns
|
185
|
+
fns = self.build_fns(fns, hooks)
|
186
|
+
|
187
|
+
# prepend scope path if we're in a scope
|
188
|
+
path = File.join(@scope[:path], path)
|
189
|
+
path = StringUtils.normalize_path(path)
|
190
|
+
|
191
|
+
# get regex and vars for path
|
192
|
+
regex, vars = self.build_route_matcher(path)
|
193
|
+
|
194
|
+
# create the route tuple
|
195
|
+
route = [regex, vars, name, fns, path]
|
196
|
+
|
197
|
+
@routes[method] << route
|
198
|
+
@routes_by_name[name] = route
|
199
|
+
|
200
|
+
# store group references if we're in a scope
|
201
|
+
return unless group = @scope[:name]
|
202
|
+
@groups[group] << route
|
203
|
+
@grouped_routes_by_name[group][name] = route
|
204
|
+
end
|
205
|
+
|
206
|
+
def parse_route_args(args)
|
207
|
+
ret = []
|
208
|
+
args.each { |arg|
|
209
|
+
if arg.is_a?(Hash) # we have hooks
|
210
|
+
ret[2] = arg
|
211
|
+
elsif arg.is_a?(Array) # we have fns
|
212
|
+
ret[1] = arg
|
213
|
+
elsif arg.is_a?(Proc) # we have a fn
|
214
|
+
ret[1] = [arg]
|
215
|
+
elsif !arg.nil? # we have a name
|
216
|
+
ret[0] = arg
|
217
|
+
end
|
218
|
+
}
|
219
|
+
ret
|
220
|
+
end
|
221
|
+
|
222
|
+
def build_fns(main_fns, hooks)
|
223
|
+
fns = []
|
224
|
+
fns.concat(hooks[:around]) if hooks && hooks[:around]
|
225
|
+
fns.concat(hooks[:before]) if hooks && hooks[:before]
|
226
|
+
fns.concat(main_fns) if main_fns
|
227
|
+
fns.concat(hooks[:after]) if hooks && hooks[:after]
|
228
|
+
fns.concat(hooks[:around]) if hooks && hooks[:around]
|
229
|
+
fns
|
230
|
+
end
|
231
|
+
|
232
|
+
def build_route_matcher(path)
|
233
|
+
return path, [] if path.is_a?(Regexp)
|
234
|
+
|
235
|
+
# check for vars
|
236
|
+
return path, [] unless path[0,1] == ':' || path.index('/:')
|
237
|
+
|
238
|
+
# we have vars
|
239
|
+
vars = []
|
240
|
+
position_counter = 1
|
241
|
+
regex_route = path
|
242
|
+
route_segments = path.split('/')
|
243
|
+
route_segments.each_with_index { |segment, i|
|
244
|
+
if segment.include?(':')
|
245
|
+
vars << { :position => position_counter, :var => segment.gsub(':', '').to_sym }
|
246
|
+
if i == route_segments.length-1 then
|
247
|
+
regex_route = regex_route.sub(segment, '((\w|[-.~:@!$\'\(\)\*\+,;])*)')
|
248
|
+
position_counter += 2
|
249
|
+
else
|
250
|
+
regex_route = regex_route.sub(segment, '((\w|[-.~:@!$\'\(\)\*\+,;])*)')
|
251
|
+
position_counter += 2
|
252
|
+
end
|
253
|
+
end
|
254
|
+
}
|
255
|
+
reg = Regexp.new("^#{regex_route}$")
|
256
|
+
return reg, vars
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
#TODO rename router to set and .func to .fn
|
2
|
+
|
3
|
+
module Pakyow
|
4
|
+
class RouteTemplate
|
5
|
+
attr_accessor :path
|
6
|
+
|
7
|
+
def initialize(block, g_name, path, router)
|
8
|
+
@fns = {}
|
9
|
+
@g_name = g_name
|
10
|
+
@path = path
|
11
|
+
@router = router
|
12
|
+
|
13
|
+
self.instance_exec(&block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def action(method, *args, &block)
|
17
|
+
fns = block_given? ? [block] : args[0]
|
18
|
+
@fns[method] = fns
|
19
|
+
end
|
20
|
+
|
21
|
+
def expand(template, data)
|
22
|
+
@expanding = true
|
23
|
+
|
24
|
+
t = self
|
25
|
+
if @path
|
26
|
+
@router.namespace(@path, @g_name) {
|
27
|
+
t.instance_exec(data, &template)
|
28
|
+
}
|
29
|
+
else
|
30
|
+
@router.group(@g_name) {
|
31
|
+
t.instance_exec(data, &template)
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def fn(name)
|
37
|
+
@expanding ? @fns[name] : @router.func(name)
|
38
|
+
end
|
39
|
+
|
40
|
+
def call(controller, action)
|
41
|
+
@router.call(controller, action)
|
42
|
+
end
|
43
|
+
|
44
|
+
def get(*args, &block)
|
45
|
+
@router.get(*args, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
def put(*args, &block)
|
49
|
+
@router.put(*args, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
def post(*args, &block)
|
53
|
+
@router.post(*args, &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
def delete(*args, &block)
|
57
|
+
@router.delete(*args, &block)
|
58
|
+
end
|
59
|
+
|
60
|
+
#TODO best name?
|
61
|
+
def map_actions(controller, actions)
|
62
|
+
actions.each { |a|
|
63
|
+
self.action(a, self.call(controller, a))
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
#TODO best name?
|
68
|
+
def map_restful_actions(controller)
|
69
|
+
self.map_actions(controller, self.restful_actions)
|
70
|
+
end
|
71
|
+
|
72
|
+
def restful_actions
|
73
|
+
[:index, :show, :new, :create, :edit, :update, :delete]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Pakyow
|
2
|
+
class RouteTemplateDefaults
|
3
|
+
def self.register
|
4
|
+
Pakyow::Router.instance.set(:default) {
|
5
|
+
template(:restful) {
|
6
|
+
get '/', :index, fn(:index)
|
7
|
+
|
8
|
+
# special case for show (view path is overridden)
|
9
|
+
if show_fns = fn(:show)
|
10
|
+
show_fns = [show_fns] unless show_fns.is_a?(Array)
|
11
|
+
get '/:id', :show, show_fns.unshift(
|
12
|
+
lambda {
|
13
|
+
presenter.view_path = File.join(self.path, 'show') if Configuration::Base.app.presenter
|
14
|
+
}
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
get '/new', :new, fn(:new)
|
19
|
+
post '/', :create, fn(:create)
|
20
|
+
|
21
|
+
get '/:id/edit', :edit, fn(:edit)
|
22
|
+
put '/:id', :update, fn(:update)
|
23
|
+
|
24
|
+
delete '/:id', :delete, fn(:delete)
|
25
|
+
}
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Pakyow
|
4
|
+
# A singleton that manages route sets.
|
5
|
+
#
|
6
|
+
class Router
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
end
|
11
|
+
|
12
|
+
def reset
|
13
|
+
@sets = {}
|
14
|
+
RouteTemplateDefaults.register
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
# Creates a new set (or appends to a set if it exists).
|
19
|
+
#
|
20
|
+
def set(name, &block)
|
21
|
+
@sets[name] ||= RouteSet.new
|
22
|
+
@sets[name].instance_exec(&block)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Iterates through route sets and returns the first matching route.
|
26
|
+
#
|
27
|
+
def route(name, group = nil)
|
28
|
+
@sets.each { |set|
|
29
|
+
if r = set[1].route(name, group)
|
30
|
+
return r
|
31
|
+
end
|
32
|
+
}
|
33
|
+
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
# Performs the initial routing for a request.
|
38
|
+
#
|
39
|
+
def route!(request)
|
40
|
+
self.trampoline(self.match(request))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Reroutes a request.
|
44
|
+
#
|
45
|
+
def reroute!(request)
|
46
|
+
throw :fns, self.match(request)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Finds and invokes a handler by name or by status code.
|
50
|
+
#
|
51
|
+
def handle!(name_or_code, from_logic = false)
|
52
|
+
@sets.each { |set|
|
53
|
+
if h = set[1].handle(name_or_code)
|
54
|
+
Pakyow.app.response.status = h[0]
|
55
|
+
from_logic ? throw(:fns, h[2]) : self.trampoline(h[2])
|
56
|
+
break
|
57
|
+
end
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def routed?
|
62
|
+
@routed
|
63
|
+
end
|
64
|
+
|
65
|
+
# Looks up and populates a path with data
|
66
|
+
#
|
67
|
+
def path(name, data = nil)
|
68
|
+
RouteLookup.new.path(name, data)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Looks up a route grouping
|
72
|
+
#
|
73
|
+
def group(name)
|
74
|
+
RouteLookup.new.group(name)
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
|
79
|
+
# Calls a list of route functions in order (each in a separate context).
|
80
|
+
#
|
81
|
+
def call_fns(fns)
|
82
|
+
fns.each {|fn| self.context.instance_exec(&fn)}
|
83
|
+
end
|
84
|
+
|
85
|
+
# Creates a context in which to evaluate a route function.
|
86
|
+
#
|
87
|
+
def context
|
88
|
+
FnContext.new
|
89
|
+
end
|
90
|
+
|
91
|
+
# Finds the first matching route for the request path/method and
|
92
|
+
# returns the list of route functions for that route.
|
93
|
+
#
|
94
|
+
def match(request)
|
95
|
+
path = StringUtils.normalize_path(request.working_path)
|
96
|
+
method = request.working_method
|
97
|
+
|
98
|
+
@routed = false
|
99
|
+
|
100
|
+
match, data = nil
|
101
|
+
@sets.each { |set|
|
102
|
+
match, data = set[1].match(path, method)
|
103
|
+
break if match
|
104
|
+
}
|
105
|
+
|
106
|
+
fns = []
|
107
|
+
if match
|
108
|
+
fns = match[3]
|
109
|
+
|
110
|
+
# handle route params
|
111
|
+
#TODO where to do this?
|
112
|
+
request.params.merge!(HashUtils.strhash(self.data_from_path(path, data, match[1])))
|
113
|
+
|
114
|
+
#TODO where to do this?
|
115
|
+
request.route_path = match[4]
|
116
|
+
end
|
117
|
+
|
118
|
+
fns
|
119
|
+
end
|
120
|
+
|
121
|
+
# Calls route functions and catches new functions as
|
122
|
+
# they're thrown (e.g. by reroute).
|
123
|
+
#
|
124
|
+
def trampoline(fns)
|
125
|
+
until fns.empty?
|
126
|
+
fns = catch(:fns) {
|
127
|
+
self.call_fns(fns)
|
128
|
+
|
129
|
+
# Getting here means that call() returned normally (not via a throw)
|
130
|
+
:fall_through
|
131
|
+
} # end :fns catch block
|
132
|
+
|
133
|
+
# If reroute! or invoke_handler! was called in the block, block will have a new value (nil or block).
|
134
|
+
# If neither was called, block will be :fall_through
|
135
|
+
|
136
|
+
@routed = case fns
|
137
|
+
when [] then false
|
138
|
+
when :fall_through then fns = [] and true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Extracts the data from a path.
|
144
|
+
#
|
145
|
+
def data_from_path(path, matches, vars)
|
146
|
+
data = {}
|
147
|
+
return data unless matches
|
148
|
+
|
149
|
+
vars.each {|v|
|
150
|
+
data[v[:var]] = matches[v[:position]]
|
151
|
+
}
|
152
|
+
|
153
|
+
data
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -5,7 +5,8 @@ module Pakyow
|
|
5
5
|
class AppGenerator
|
6
6
|
class << self
|
7
7
|
def start
|
8
|
-
|
8
|
+
case ARGV.first
|
9
|
+
when '--help', '-h', nil
|
9
10
|
puts File.open(File.join(CORE_PATH, 'commands/USAGE-NEW')).read
|
10
11
|
else
|
11
12
|
generator = self.new
|
@@ -19,7 +20,16 @@ module Pakyow
|
|
19
20
|
end
|
20
21
|
|
21
22
|
def build(dest)
|
22
|
-
|
23
|
+
if !File.directory?(dest) || (Dir.entries(dest) - ['.', '..']).empty?
|
24
|
+
FileUtils.cp_r(@src, dest)
|
25
|
+
else
|
26
|
+
ARGV.clear
|
27
|
+
print "The folder '#{dest}' is in use. Would you like to populate it anyway? [Yn] "
|
28
|
+
|
29
|
+
if gets.chomp! == 'Y'
|
30
|
+
FileUtils.cp_r(@src, dest)
|
31
|
+
end
|
32
|
+
end
|
23
33
|
end
|
24
34
|
end
|
25
35
|
end
|
@@ -1,2 +1,2 @@
|
|
1
|
-
require File.expand_path('
|
1
|
+
require File.expand_path('application', __FILE__)
|
2
2
|
PakyowApplication::Application.stage(ENV['ENV'])
|
File without changes
|
@@ -3,16 +3,6 @@ module Pakyow
|
|
3
3
|
# Utility methods for strings.
|
4
4
|
class StringUtils
|
5
5
|
|
6
|
-
# Creates an underscored, lowercase version of a string.
|
7
|
-
# This was borrowed from another library, probably ActiveSupport.
|
8
|
-
def self.underscore(string)
|
9
|
-
string.gsub(/::/, '/').
|
10
|
-
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
11
|
-
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
12
|
-
tr("-", "_").
|
13
|
-
downcase
|
14
|
-
end
|
15
|
-
|
16
6
|
# split . seperated string at the last .
|
17
7
|
def self.split_at_last_dot(s)
|
18
8
|
split_index = s.rindex('.')
|
@@ -32,6 +22,17 @@ module Pakyow
|
|
32
22
|
return ret
|
33
23
|
end
|
34
24
|
|
25
|
+
def self.parse_path_from_caller(caller)
|
26
|
+
caller.match(/^(.+)(:?:\d+(:?:in `.+')?$)/)[1]
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.normalize_path(path)
|
30
|
+
return path if path.is_a?(Regexp)
|
31
|
+
|
32
|
+
path = path[1, path.length - 1] if path[0, 1] == '/'
|
33
|
+
path = path[0, path.length - 1] if path[path.length - 1, 1] == '/'
|
34
|
+
path
|
35
|
+
end
|
35
36
|
|
36
37
|
end
|
37
38
|
end
|