wycats-merb-core 0.9.8
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/CHANGELOG +992 -0
- data/CONTRIBUTORS +94 -0
- data/LICENSE +20 -0
- data/PUBLIC_CHANGELOG +142 -0
- data/README +21 -0
- data/Rakefile +458 -0
- data/TODO +0 -0
- data/bin/merb +11 -0
- data/bin/merb-specs +5 -0
- data/lib/merb-core.rb +598 -0
- data/lib/merb-core/autoload.rb +31 -0
- data/lib/merb-core/bootloader.rb +717 -0
- data/lib/merb-core/config.rb +305 -0
- data/lib/merb-core/constants.rb +45 -0
- data/lib/merb-core/controller/abstract_controller.rb +568 -0
- data/lib/merb-core/controller/exceptions.rb +315 -0
- data/lib/merb-core/controller/merb_controller.rb +256 -0
- data/lib/merb-core/controller/mime.rb +107 -0
- data/lib/merb-core/controller/mixins/authentication.rb +123 -0
- data/lib/merb-core/controller/mixins/conditional_get.rb +83 -0
- data/lib/merb-core/controller/mixins/controller.rb +319 -0
- data/lib/merb-core/controller/mixins/render.rb +513 -0
- data/lib/merb-core/controller/mixins/responder.rb +469 -0
- data/lib/merb-core/controller/template.rb +254 -0
- data/lib/merb-core/core_ext.rb +9 -0
- data/lib/merb-core/core_ext/hash.rb +7 -0
- data/lib/merb-core/core_ext/kernel.rb +340 -0
- data/lib/merb-core/dispatch/cookies.rb +130 -0
- data/lib/merb-core/dispatch/default_exception/default_exception.rb +93 -0
- data/lib/merb-core/dispatch/default_exception/views/_css.html.erb +198 -0
- data/lib/merb-core/dispatch/default_exception/views/_javascript.html.erb +73 -0
- data/lib/merb-core/dispatch/default_exception/views/index.html.erb +94 -0
- data/lib/merb-core/dispatch/dispatcher.rb +176 -0
- data/lib/merb-core/dispatch/request.rb +729 -0
- data/lib/merb-core/dispatch/router.rb +151 -0
- data/lib/merb-core/dispatch/router/behavior.rb +566 -0
- data/lib/merb-core/dispatch/router/cached_proc.rb +52 -0
- data/lib/merb-core/dispatch/router/resources.rb +191 -0
- data/lib/merb-core/dispatch/router/route.rb +511 -0
- data/lib/merb-core/dispatch/session.rb +222 -0
- data/lib/merb-core/dispatch/session/container.rb +74 -0
- data/lib/merb-core/dispatch/session/cookie.rb +173 -0
- data/lib/merb-core/dispatch/session/memcached.rb +68 -0
- data/lib/merb-core/dispatch/session/memory.rb +99 -0
- data/lib/merb-core/dispatch/session/store_container.rb +150 -0
- data/lib/merb-core/dispatch/worker.rb +28 -0
- data/lib/merb-core/gem_ext/erubis.rb +77 -0
- data/lib/merb-core/logger.rb +203 -0
- data/lib/merb-core/plugins.rb +67 -0
- data/lib/merb-core/rack.rb +25 -0
- data/lib/merb-core/rack/adapter.rb +44 -0
- data/lib/merb-core/rack/adapter/ebb.rb +25 -0
- data/lib/merb-core/rack/adapter/evented_mongrel.rb +26 -0
- data/lib/merb-core/rack/adapter/fcgi.rb +17 -0
- data/lib/merb-core/rack/adapter/irb.rb +118 -0
- data/lib/merb-core/rack/adapter/mongrel.rb +26 -0
- data/lib/merb-core/rack/adapter/runner.rb +28 -0
- data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +26 -0
- data/lib/merb-core/rack/adapter/thin.rb +39 -0
- data/lib/merb-core/rack/adapter/thin_turbo.rb +24 -0
- data/lib/merb-core/rack/adapter/webrick.rb +36 -0
- data/lib/merb-core/rack/application.rb +32 -0
- data/lib/merb-core/rack/handler/mongrel.rb +97 -0
- data/lib/merb-core/rack/middleware.rb +20 -0
- data/lib/merb-core/rack/middleware/conditional_get.rb +29 -0
- data/lib/merb-core/rack/middleware/content_length.rb +18 -0
- data/lib/merb-core/rack/middleware/csrf.rb +73 -0
- data/lib/merb-core/rack/middleware/path_prefix.rb +31 -0
- data/lib/merb-core/rack/middleware/profiler.rb +19 -0
- data/lib/merb-core/rack/middleware/static.rb +45 -0
- data/lib/merb-core/rack/middleware/tracer.rb +20 -0
- data/lib/merb-core/server.rb +284 -0
- data/lib/merb-core/tasks/audit.rake +68 -0
- data/lib/merb-core/tasks/gem_management.rb +229 -0
- data/lib/merb-core/tasks/merb.rb +1 -0
- data/lib/merb-core/tasks/merb_rake_helper.rb +80 -0
- data/lib/merb-core/tasks/stats.rake +71 -0
- data/lib/merb-core/test.rb +11 -0
- data/lib/merb-core/test/helpers.rb +9 -0
- data/lib/merb-core/test/helpers/controller_helper.rb +8 -0
- data/lib/merb-core/test/helpers/multipart_request_helper.rb +175 -0
- data/lib/merb-core/test/helpers/request_helper.rb +393 -0
- data/lib/merb-core/test/helpers/route_helper.rb +39 -0
- data/lib/merb-core/test/helpers/view_helper.rb +121 -0
- data/lib/merb-core/test/matchers.rb +9 -0
- data/lib/merb-core/test/matchers/controller_matchers.rb +351 -0
- data/lib/merb-core/test/matchers/route_matchers.rb +137 -0
- data/lib/merb-core/test/matchers/view_matchers.rb +375 -0
- data/lib/merb-core/test/run_specs.rb +49 -0
- data/lib/merb-core/test/tasks/spectasks.rb +68 -0
- data/lib/merb-core/test/test_ext/hpricot.rb +32 -0
- data/lib/merb-core/test/test_ext/object.rb +14 -0
- data/lib/merb-core/test/test_ext/string.rb +14 -0
- data/lib/merb-core/vendor/facets.rb +2 -0
- data/lib/merb-core/vendor/facets/dictionary.rb +433 -0
- data/lib/merb-core/vendor/facets/inflect.rb +342 -0
- data/lib/merb-core/version.rb +3 -0
- metadata +253 -0
@@ -0,0 +1,254 @@
|
|
1
|
+
module Merb::InlineTemplates
|
2
|
+
end
|
3
|
+
|
4
|
+
module Merb::Template
|
5
|
+
|
6
|
+
EXTENSIONS = {} unless defined?(EXTENSIONS)
|
7
|
+
METHOD_LIST = {} unless defined?(METHOD_LIST)
|
8
|
+
MTIMES = {} unless defined?(MTIMES)
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# Get the template's method name from a full path. This replaces
|
12
|
+
# non-alphanumeric characters with __ and "." with "_"
|
13
|
+
#
|
14
|
+
# Collisions are potentially possible with something like:
|
15
|
+
# ~foo.bar and __foo.bar or !foo.bar.
|
16
|
+
#
|
17
|
+
# ==== Parameters
|
18
|
+
# path<String>:: A full path to convert to a valid Ruby method name
|
19
|
+
#
|
20
|
+
# ==== Returns
|
21
|
+
# String:: The template name.
|
22
|
+
#
|
23
|
+
#---
|
24
|
+
# We might want to replace this with something that varies the
|
25
|
+
# character replaced based on the non-alphanumeric character
|
26
|
+
# to avoid edge-case collisions.
|
27
|
+
def template_name(path)
|
28
|
+
path = File.expand_path(path)
|
29
|
+
path.gsub(/[^\.a-zA-Z0-9]/, "__").gsub(/\./, "_")
|
30
|
+
end
|
31
|
+
|
32
|
+
# For a given path, get an IO object that responds to #path.
|
33
|
+
#
|
34
|
+
# This is so that plugins can override this if they provide
|
35
|
+
# mechanisms for specifying templates that are not just simple
|
36
|
+
# files. The plugin is responsible for ensuring that the fake
|
37
|
+
# path provided will work with #template_for, and thus the
|
38
|
+
# RenderMixin in general.
|
39
|
+
#
|
40
|
+
# ==== Parameters
|
41
|
+
# path<String>:: A full path to find a template for. This is the
|
42
|
+
# path that the RenderMixin assumes it should find the template
|
43
|
+
# in.
|
44
|
+
#
|
45
|
+
# ==== Returns
|
46
|
+
# IO#path:: An IO object that responds to path (File or VirtualFile).
|
47
|
+
#---
|
48
|
+
# @semipublic
|
49
|
+
def load_template_io(path)
|
50
|
+
File.open(path, "r")
|
51
|
+
end
|
52
|
+
|
53
|
+
# Get the name of the template method for a particular path.
|
54
|
+
#
|
55
|
+
# ==== Parameters
|
56
|
+
# path<String>:: A full path to find a template method for.
|
57
|
+
# template_stack<Array>:: The template stack. Not used.
|
58
|
+
#
|
59
|
+
# ==== Returns
|
60
|
+
# <String>:: name of the method that inlines the template.
|
61
|
+
#---
|
62
|
+
# @semipublic
|
63
|
+
def template_for(path, template_stack = [])
|
64
|
+
path = File.expand_path(path)
|
65
|
+
|
66
|
+
ret =
|
67
|
+
if Merb::Config[:reload_templates]
|
68
|
+
file = Dir["#{path}.{#{template_extensions.join(',')}}"].first
|
69
|
+
METHOD_LIST[path] = file ? inline_template(load_template_io(file)) : nil
|
70
|
+
else
|
71
|
+
METHOD_LIST[path] ||= begin
|
72
|
+
file = Dir["#{path}.{#{template_extensions.join(',')}}"].first
|
73
|
+
file ? inline_template(load_template_io(file)) : nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
ret
|
78
|
+
end
|
79
|
+
|
80
|
+
# Get all known template extensions
|
81
|
+
#
|
82
|
+
# ==== Returns
|
83
|
+
# Array:: Extension strings.
|
84
|
+
#---
|
85
|
+
# @semipublic
|
86
|
+
def template_extensions
|
87
|
+
EXTENSIONS.keys
|
88
|
+
end
|
89
|
+
|
90
|
+
# Takes a template at a particular path and inlines it into a module and
|
91
|
+
# adds it to the METHOD_LIST table to speed lookup later.
|
92
|
+
#
|
93
|
+
# ==== Parameters
|
94
|
+
# io<#path>::
|
95
|
+
# An IO that responds to #path (File or VirtualFile)
|
96
|
+
# mod<Module>::
|
97
|
+
# The module to put the compiled method into. Defaults to
|
98
|
+
# Merb::InlineTemplates
|
99
|
+
#
|
100
|
+
# ==== Notes
|
101
|
+
# Even though this method supports inlining into any module, the method
|
102
|
+
# must be available to instances of AbstractController that will use it.
|
103
|
+
#---
|
104
|
+
# @public
|
105
|
+
def inline_template(io, mod = Merb::InlineTemplates)
|
106
|
+
path = File.expand_path(io.path)
|
107
|
+
ret = METHOD_LIST[path.gsub(/\.[^\.]*$/, "")] =
|
108
|
+
engine_for(path).compile_template(io, template_name(path), mod)
|
109
|
+
io.close
|
110
|
+
ret
|
111
|
+
end
|
112
|
+
|
113
|
+
# Finds the engine for a particular path.
|
114
|
+
#
|
115
|
+
# ==== Parameters
|
116
|
+
# path<String>:: The path of the file to find an engine for.
|
117
|
+
#
|
118
|
+
# ==== Returns
|
119
|
+
# Class:: The engine.
|
120
|
+
#---
|
121
|
+
# @semipublic
|
122
|
+
def engine_for(path)
|
123
|
+
path = File.expand_path(path)
|
124
|
+
EXTENSIONS[path.match(/\.([^\.]*)$/)[1]]
|
125
|
+
end
|
126
|
+
|
127
|
+
# Registers the extensions that will trigger a particular templating
|
128
|
+
# engine.
|
129
|
+
#
|
130
|
+
# ==== Parameters
|
131
|
+
# engine<Class>:: The class of the engine that is being registered
|
132
|
+
# extensions<Array[String]>::
|
133
|
+
# The list of extensions that will be registered with this templating
|
134
|
+
# language
|
135
|
+
#
|
136
|
+
# ==== Raises
|
137
|
+
# ArgumentError:: engine does not have a compile_template method.
|
138
|
+
#
|
139
|
+
# ==== Example
|
140
|
+
# Merb::Template.register_extensions(Merb::Template::Erubis, ["erb"])
|
141
|
+
#---
|
142
|
+
# @public
|
143
|
+
def register_extensions(engine, extensions)
|
144
|
+
raise ArgumentError, "The class you are registering does not have a compile_template method" unless
|
145
|
+
engine.respond_to?(:compile_template)
|
146
|
+
extensions.each{|ext| EXTENSIONS[ext] = engine }
|
147
|
+
Merb::AbstractController.class_eval <<-HERE
|
148
|
+
include #{engine}::Mixin
|
149
|
+
HERE
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
require 'erubis'
|
154
|
+
|
155
|
+
class Erubis
|
156
|
+
# ==== Parameters
|
157
|
+
# io<#path>:: An IO containing the full path of the template.
|
158
|
+
# name<String>:: The name of the method that will be created.
|
159
|
+
# mod<Module>:: The module that the compiled method will be placed into.
|
160
|
+
def self.compile_template(io, name, mod)
|
161
|
+
template = ::Erubis::BlockAwareEruby.new(io.read)
|
162
|
+
|
163
|
+
_old_verbose, $VERBOSE = $VERBOSE, nil
|
164
|
+
template.def_method(mod, name, File.expand_path(io.path))
|
165
|
+
$VERBOSE = _old_verbose
|
166
|
+
|
167
|
+
name
|
168
|
+
end
|
169
|
+
|
170
|
+
module Mixin
|
171
|
+
|
172
|
+
# ==== Parameters
|
173
|
+
# *args:: Arguments to pass to the block.
|
174
|
+
# &block:: The template block to call.
|
175
|
+
#
|
176
|
+
# ==== Returns
|
177
|
+
# String:: The output of the block.
|
178
|
+
#
|
179
|
+
# ==== Examples
|
180
|
+
# Capture being used in a .html.erb page:
|
181
|
+
#
|
182
|
+
# <% @foo = capture do %>
|
183
|
+
# <p>Some Foo content!</p>
|
184
|
+
# <% end %>
|
185
|
+
def capture_erb(*args, &block)
|
186
|
+
_old_buf, @_erb_buf = @_erb_buf, ""
|
187
|
+
block.call(*args)
|
188
|
+
ret = @_erb_buf
|
189
|
+
@_erb_buf = _old_buf
|
190
|
+
ret
|
191
|
+
end
|
192
|
+
|
193
|
+
# DOC
|
194
|
+
def concat_erb(string, binding)
|
195
|
+
@_erb_buf << string
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
Merb::Template.register_extensions(self, %w[erb])
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
module Erubis
|
206
|
+
module BlockAwareEnhancer
|
207
|
+
def add_preamble(src)
|
208
|
+
src << "_old_buf, @_erb_buf = @_erb_buf, ''; "
|
209
|
+
src << "@_engine = 'erb'; "
|
210
|
+
end
|
211
|
+
|
212
|
+
def add_postamble(src)
|
213
|
+
src << "\n" unless src[-1] == ?\n
|
214
|
+
src << "_ret = @_erb_buf; @_erb_buf = _old_buf; _ret.to_s;\n"
|
215
|
+
end
|
216
|
+
|
217
|
+
def add_text(src, text)
|
218
|
+
src << " @_erb_buf.concat('" << escape_text(text) << "'); "
|
219
|
+
end
|
220
|
+
|
221
|
+
def add_expr_escaped(src, code)
|
222
|
+
src << ' @_erb_buf.concat(' << escaped_expr(code) << ');'
|
223
|
+
end
|
224
|
+
|
225
|
+
def add_stmt2(src, code, tailch)
|
226
|
+
src << code
|
227
|
+
src << " ).to_s; " if tailch == "="
|
228
|
+
src << ';' unless code[-1] == ?\n
|
229
|
+
end
|
230
|
+
|
231
|
+
def add_expr_literal(src, code)
|
232
|
+
if code =~ /(do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
233
|
+
src << ' @_erb_buf.concat( ' << code << "; "
|
234
|
+
else
|
235
|
+
src << ' @_erb_buf.concat((' << code << ').to_s);'
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
class BlockAwareEruby < Eruby
|
241
|
+
include BlockAwareEnhancer
|
242
|
+
end
|
243
|
+
|
244
|
+
# module RubyEvaluator
|
245
|
+
#
|
246
|
+
# # DOC
|
247
|
+
# def def_method(object, method_name, filename=nil)
|
248
|
+
# m = object.is_a?(Module) ? :module_eval : :instance_eval
|
249
|
+
# setup = "@_engine = 'erb'"
|
250
|
+
# object.__send__(m, "def #{method_name}(locals={}); #{setup}; #{@src}; end", filename || @filename || '(erubis)')
|
251
|
+
# end
|
252
|
+
#
|
253
|
+
# end
|
254
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
begin
|
2
|
+
require "extlib"
|
3
|
+
rescue LoadError => e
|
4
|
+
puts "Merb-core 0.9.4 and later uses extlib for Ruby core class extensions. Install it from github.com/sam/extlib."
|
5
|
+
exit
|
6
|
+
end
|
7
|
+
|
8
|
+
require File.dirname(__FILE__) / "core_ext" / "kernel"
|
9
|
+
require File.dirname(__FILE__) / "core_ext" / "hash"
|
@@ -0,0 +1,340 @@
|
|
1
|
+
require 'rubygems/dependency'
|
2
|
+
|
3
|
+
module Kernel
|
4
|
+
|
5
|
+
# Keep track of all required dependencies.
|
6
|
+
#
|
7
|
+
# @param name<String> The name of the gem to load.
|
8
|
+
# @param *ver<Gem::Requirement, Gem::Version, Array, #to_str>
|
9
|
+
# Version requirements to be passed to Gem::Dependency.new.
|
10
|
+
#
|
11
|
+
# @return <Gem::Dependency> Dependency information
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
def track_dependency(name, *ver)
|
15
|
+
dep = Gem::Dependency.new(name, ver)
|
16
|
+
existing = Merb::BootLoader::Dependencies.dependencies.find { |d| d.name == dep.name }
|
17
|
+
if existing
|
18
|
+
index = Merb::BootLoader::Dependencies.dependencies.index(existing)
|
19
|
+
Merb::BootLoader::Dependencies.dependencies.delete(existing)
|
20
|
+
Merb::BootLoader::Dependencies.dependencies.insert(index, dep)
|
21
|
+
else
|
22
|
+
Merb::BootLoader::Dependencies.dependencies << dep
|
23
|
+
end
|
24
|
+
return dep
|
25
|
+
end
|
26
|
+
|
27
|
+
# Loads the given string as a gem. Execution is deferred until
|
28
|
+
# after the logger has been instantiated and the framework directory
|
29
|
+
# structure is defined.
|
30
|
+
#
|
31
|
+
# If that has already happened, the gem will be activated
|
32
|
+
# immediately, but it will still be registered.
|
33
|
+
#
|
34
|
+
# @param name<String> The name of the gem to load.
|
35
|
+
# @param *ver<Gem::Requirement, Gem::Version, Array, #to_str>
|
36
|
+
# Version requirements to be passed to Gem::Dependency.new.
|
37
|
+
#
|
38
|
+
# @return <Gem::Dependency> The dependency information.
|
39
|
+
def dependency(name, *ver)
|
40
|
+
if Merb::BootLoader.finished?(Merb::BootLoader::Dependencies)
|
41
|
+
load_dependency(name, *ver)
|
42
|
+
else
|
43
|
+
track_dependency(name, *ver)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Loads the given string as a gem.
|
48
|
+
#
|
49
|
+
# This new version tries to load the file via ROOT/gems first before moving
|
50
|
+
# off to the system gems (so if you have a lower version of a gem in
|
51
|
+
# ROOT/gems, it'll still get loaded).
|
52
|
+
#
|
53
|
+
# @param name<String,Gem::Dependency>
|
54
|
+
# The name or dependency object of the gem to load.
|
55
|
+
# @param *ver<Gem::Requirement, Gem::Version, Array, #to_str>
|
56
|
+
# Version requirements to be passed to Gem.activate.
|
57
|
+
#
|
58
|
+
# @note
|
59
|
+
# If the gem cannot be found, the method will attempt to require the string
|
60
|
+
# as a library.
|
61
|
+
#
|
62
|
+
# @return <Gem::Dependency> The dependency information.
|
63
|
+
def load_dependency(name, *ver)
|
64
|
+
dep = name.is_a?(Gem::Dependency) ? name : track_dependency(name, *ver)
|
65
|
+
gem(dep)
|
66
|
+
rescue Gem::LoadError
|
67
|
+
ensure
|
68
|
+
require dep.name
|
69
|
+
Merb.logger.info!("loading gem '#{dep.name}' ...")
|
70
|
+
return dep # ensure needs explicit return
|
71
|
+
end
|
72
|
+
|
73
|
+
# Loads both gem and library dependencies that are passed in as arguments.
|
74
|
+
# Execution is deferred to the Merb::BootLoader::Dependencies.run during bootup.
|
75
|
+
#
|
76
|
+
# @param *args<String, Hash, Array> The dependencies to load.
|
77
|
+
def dependencies(*args)
|
78
|
+
args.map do |arg|
|
79
|
+
case arg
|
80
|
+
when String then dependency(arg)
|
81
|
+
when Hash then arg.map { |r,v| dependency(r, v) }
|
82
|
+
when Array then arg.map { |r| dependency(r) }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Loads both gem and library dependencies that are passed in as arguments.
|
88
|
+
#
|
89
|
+
# @param *args<String, Hash, Array> The dependencies to load.
|
90
|
+
#
|
91
|
+
# @note
|
92
|
+
# Each argument can be:
|
93
|
+
# String:: Single dependency.
|
94
|
+
# Hash::
|
95
|
+
# Multiple dependencies where the keys are names and the values versions.
|
96
|
+
# Array:: Multiple string dependencies.
|
97
|
+
#
|
98
|
+
# @example dependencies "RedCloth" # Loads the the RedCloth gem
|
99
|
+
# @example dependencies "RedCloth", "merb_helpers" # Loads RedCloth and merb_helpers
|
100
|
+
# @example dependencies "RedCloth" => "3.0" # Loads RedCloth 3.0
|
101
|
+
def load_dependencies(*args)
|
102
|
+
args.map do |arg|
|
103
|
+
case arg
|
104
|
+
when String then load_dependency(arg)
|
105
|
+
when Hash then arg.map { |r,v| load_dependency(r, v) }
|
106
|
+
when Array then arg.map { |r| load_dependency(r) }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Does a basic require, and prints a message if an error occurs.
|
112
|
+
#
|
113
|
+
# @param library<to_s> The library to attempt to include.
|
114
|
+
# @param message<String> The error to add to the log upon failure. Defaults to nil.
|
115
|
+
def rescue_require(library, message = nil)
|
116
|
+
require library
|
117
|
+
rescue LoadError, RuntimeError
|
118
|
+
Merb.logger.error!(message) if message
|
119
|
+
end
|
120
|
+
|
121
|
+
# Used in Merb.root/config/init.rb to tell Merb which ORM (Object Relational
|
122
|
+
# Mapper) you wish to use. Currently Merb has plugins to support
|
123
|
+
# ActiveRecord, DataMapper, and Sequel.
|
124
|
+
#
|
125
|
+
# @param orm<Symbol> The ORM to use.
|
126
|
+
#
|
127
|
+
# @example
|
128
|
+
# use_orm :datamapper
|
129
|
+
#
|
130
|
+
# # This will use the DataMapper generator for your ORM
|
131
|
+
# $ merb-gen model ActivityEvent
|
132
|
+
#
|
133
|
+
# @note
|
134
|
+
# If for some reason this is called more than once, latter
|
135
|
+
# call takes over other.
|
136
|
+
# @api public
|
137
|
+
def use_orm(orm)
|
138
|
+
begin
|
139
|
+
Merb.orm = orm
|
140
|
+
orm_plugin = "merb_#{orm}"
|
141
|
+
Kernel.dependency(orm_plugin)
|
142
|
+
rescue LoadError => e
|
143
|
+
Merb.logger.warn!("The #{orm_plugin} gem was not found. You may need to install it.")
|
144
|
+
raise e
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Used in Merb.root/config/init.rb to tell Merb which testing framework to
|
149
|
+
# use. Currently Merb has plugins to support RSpec and Test::Unit.
|
150
|
+
#
|
151
|
+
# @param test_framework<Symbol>
|
152
|
+
# The test framework to use. Currently only supports :rspec and :test_unit.
|
153
|
+
#
|
154
|
+
# @example
|
155
|
+
# use_test :rspec
|
156
|
+
#
|
157
|
+
# # This will now use the RSpec generator for tests
|
158
|
+
# $ merb-gen model ActivityEvent
|
159
|
+
# @api public
|
160
|
+
def use_test(test_framework, *test_dependencies)
|
161
|
+
Merb.test_framework = test_framework
|
162
|
+
|
163
|
+
Kernel.dependencies test_dependencies if Merb.env == "test" || Merb.env.nil?
|
164
|
+
end
|
165
|
+
|
166
|
+
# Used in Merb.root/config/init.rb to tell Merb which template engine to
|
167
|
+
# prefer.
|
168
|
+
#
|
169
|
+
# @param template_engine<Symbol>
|
170
|
+
# The template engine to use.
|
171
|
+
#
|
172
|
+
# @example
|
173
|
+
# use_template_engine :haml
|
174
|
+
#
|
175
|
+
# # This will now use haml templates in generators where available.
|
176
|
+
# $ merb-gen resource_controller Project
|
177
|
+
# @api public
|
178
|
+
def use_template_engine(template_engine)
|
179
|
+
Merb.template_engine = template_engine
|
180
|
+
|
181
|
+
if template_engine != :erb
|
182
|
+
if template_engine.in?(:haml, :builder)
|
183
|
+
template_engine_plugin = "merb-#{template_engine}"
|
184
|
+
else
|
185
|
+
template_engine_plugin = "merb_#{template_engine}"
|
186
|
+
end
|
187
|
+
Kernel.dependency(template_engine_plugin)
|
188
|
+
end
|
189
|
+
rescue LoadError => e
|
190
|
+
Merb.logger.warn!("The #{template_engine_plugin} gem was not found. You may need to install it.")
|
191
|
+
raise e
|
192
|
+
end
|
193
|
+
|
194
|
+
# @param i<Fixnum> The caller number. Defaults to 1.
|
195
|
+
#
|
196
|
+
# @return <Array[Array]> The file, line and method of the caller.
|
197
|
+
#
|
198
|
+
# @example
|
199
|
+
# __caller_info__(1)
|
200
|
+
# # => ['/usr/lib/ruby/1.8/irb/workspace.rb', '52', 'irb_binding']
|
201
|
+
def __caller_info__(i = 1)
|
202
|
+
file, line, meth = caller[i].scan(/(.*?):(\d+):in `(.*?)'/).first
|
203
|
+
end
|
204
|
+
|
205
|
+
# @param file<String> The file to read.
|
206
|
+
# @param line<Fixnum> The line number to look for.
|
207
|
+
# @param size<Fixnum>
|
208
|
+
# Number of lines to include above and below the the line to look for.
|
209
|
+
# Defaults to 4.
|
210
|
+
#
|
211
|
+
# @return <Array[Array]>
|
212
|
+
# Triplets containing the line number, the line and whether this was the
|
213
|
+
# searched line.
|
214
|
+
#
|
215
|
+
# @example
|
216
|
+
# __caller_lines__('/usr/lib/ruby/1.8/debug.rb', 122, 2) # =>
|
217
|
+
# [
|
218
|
+
# [ 120, " def check_suspend", false ],
|
219
|
+
# [ 121, " return if Thread.critical", false ],
|
220
|
+
# [ 122, " while (Thread.critical = true; @suspend_next)", true ],
|
221
|
+
# [ 123, " DEBUGGER__.waiting.push Thread.current", false ],
|
222
|
+
# [ 124, " @suspend_next = false", false ]
|
223
|
+
# ]
|
224
|
+
def __caller_lines__(file, line, size = 4)
|
225
|
+
line = line.to_i
|
226
|
+
if file =~ /\(erubis\)/
|
227
|
+
yield :error, "Template Error! Problem while rendering", false
|
228
|
+
elsif !File.file?(file) || !File.readable?(file)
|
229
|
+
yield :error, "File `#{file}' not available", false
|
230
|
+
else
|
231
|
+
lines = File.read(file).split("\n")
|
232
|
+
first_line = (f = line - size - 1) < 0 ? 0 : f
|
233
|
+
lines = lines[first_line, size * 2 + 1]
|
234
|
+
|
235
|
+
lines.each_with_index do |str, index|
|
236
|
+
yield index + line - size, str.chomp
|
237
|
+
end
|
238
|
+
end
|
239
|
+
#
|
240
|
+
# lines = File.readlines(file)
|
241
|
+
# current = line.to_i - 1
|
242
|
+
#
|
243
|
+
# first = current - size
|
244
|
+
# first = first < 0 ? 0 : first
|
245
|
+
#
|
246
|
+
# last = current + size
|
247
|
+
# last = last > lines.size ? lines.size : last
|
248
|
+
#
|
249
|
+
# log = lines[first..last]
|
250
|
+
#
|
251
|
+
# area = []
|
252
|
+
#
|
253
|
+
# log.each_with_index do |line, index|
|
254
|
+
# index = index + first + 1
|
255
|
+
# area << [index, line.chomp, index == current + 1]
|
256
|
+
# end
|
257
|
+
#
|
258
|
+
# area
|
259
|
+
end
|
260
|
+
|
261
|
+
# Takes a block, profiles the results of running the block
|
262
|
+
# specified number of times and generates HTML report.
|
263
|
+
#
|
264
|
+
# @param name<#to_s>
|
265
|
+
# The file name. The result will be written out to
|
266
|
+
# Merb.root/"log/#{name}.html".
|
267
|
+
# @param min<Fixnum>
|
268
|
+
# Minimum percentage of the total time a method must take for it to be
|
269
|
+
# included in the result. Defaults to 1.
|
270
|
+
#
|
271
|
+
# @return <String>
|
272
|
+
# The result of the profiling.
|
273
|
+
#
|
274
|
+
# @note
|
275
|
+
# Requires ruby-prof (<tt>sudo gem install ruby-prof</tt>)
|
276
|
+
#
|
277
|
+
# @example
|
278
|
+
# __profile__("MyProfile", 5, 30) do
|
279
|
+
# rand(10)**rand(10)
|
280
|
+
# puts "Profile run"
|
281
|
+
# end
|
282
|
+
#
|
283
|
+
# Assuming that the total time taken for #puts calls was less than 5% of the
|
284
|
+
# total time to run, #puts won't appear in the profile report.
|
285
|
+
# The code block will be run 30 times in the example above.
|
286
|
+
def __profile__(name, min=1, iter=100)
|
287
|
+
require 'ruby-prof' unless defined?(RubyProf)
|
288
|
+
return_result = ''
|
289
|
+
result = RubyProf.profile do
|
290
|
+
iter.times{return_result = yield}
|
291
|
+
end
|
292
|
+
printer = RubyProf::GraphHtmlPrinter.new(result)
|
293
|
+
path = File.join(Merb.root, 'log', "#{name}.html")
|
294
|
+
File.open(path, 'w') do |file|
|
295
|
+
printer.print(file, {:min_percent => min,
|
296
|
+
:print_file => true})
|
297
|
+
end
|
298
|
+
return_result
|
299
|
+
end
|
300
|
+
|
301
|
+
# Extracts an options hash if it is the last item in the args array. Used
|
302
|
+
# internally in methods that take *args.
|
303
|
+
#
|
304
|
+
# @param args<Array> The arguments to extract the hash from.
|
305
|
+
#
|
306
|
+
# @example
|
307
|
+
# def render(*args,&blk)
|
308
|
+
# opts = extract_options_from_args!(args) || {}
|
309
|
+
# # [...]
|
310
|
+
# end
|
311
|
+
def extract_options_from_args!(args)
|
312
|
+
args.pop if Hash === args.last
|
313
|
+
end
|
314
|
+
|
315
|
+
# Checks that the given objects quack like the given conditions.
|
316
|
+
#
|
317
|
+
# @param opts<Hash>
|
318
|
+
# Conditions to enforce. Each key will receive a quacks_like? call with the
|
319
|
+
# value (see Object#quacks_like? for details).
|
320
|
+
#
|
321
|
+
# @raise <ArgumentError>
|
322
|
+
# An object failed to quack like a condition.
|
323
|
+
def enforce!(opts = {})
|
324
|
+
opts.each do |k,v|
|
325
|
+
raise ArgumentError, "#{k.inspect} doesn't quack like #{v.inspect}" unless k.quacks_like?(v)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
unless Kernel.respond_to?(:debugger)
|
330
|
+
|
331
|
+
# Define debugger method so that code even works if debugger was not
|
332
|
+
# requested. Drops a note to the logs that Debugger was not available.
|
333
|
+
def debugger
|
334
|
+
Merb.logger.info! "\n***** Debugger requested, but was not " +
|
335
|
+
"available: Start server with --debugger " +
|
336
|
+
"to enable *****\n"
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
end
|