instiki 0.9.2 → 0.10.0
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 +165 -0
- data/README +68 -172
- data/app/controllers/admin_controller.rb +94 -0
- data/app/controllers/application.rb +131 -0
- data/app/controllers/file_controller.rb +129 -0
- data/app/controllers/wiki_controller.rb +354 -0
- data/{libraries/view_helper.rb → app/helpers/application_helper.rb} +68 -33
- data/app/models/author.rb +3 -3
- data/app/models/chunks/category.rb +33 -31
- data/app/models/chunks/chunk.rb +86 -20
- data/app/models/chunks/engines.rb +54 -38
- data/app/models/chunks/include.rb +41 -29
- data/app/models/chunks/literal.rb +31 -19
- data/app/models/chunks/nowiki.rb +28 -31
- data/app/models/chunks/test.rb +18 -18
- data/app/models/chunks/uri.rb +182 -97
- data/app/models/chunks/wiki.rb +141 -82
- data/app/models/file_yard.rb +58 -0
- data/app/models/page.rb +112 -86
- data/app/models/page_lock.rb +22 -23
- data/app/models/page_set.rb +89 -64
- data/app/models/revision.rb +123 -90
- data/app/models/web.rb +176 -89
- data/app/models/wiki_content.rb +207 -105
- data/app/models/wiki_service.rb +233 -83
- data/app/models/wiki_words.rb +23 -25
- data/app/views/{wiki/new_system.rhtml → admin/create_system.rhtml} +83 -78
- data/app/views/{wiki/new_web.rhtml → admin/create_web.rhtml} +69 -64
- data/app/views/admin/edit_web.rhtml +136 -0
- data/app/views/file/file.rhtml +19 -0
- data/app/views/file/import.rhtml +23 -0
- data/app/views/layouts/default.rhtml +85 -0
- data/app/views/markdown_help.rhtml +12 -16
- data/app/views/mixed_help.rhtml +7 -0
- data/app/views/navigation.rhtml +30 -19
- data/app/views/rdoc_help.rhtml +12 -16
- data/app/views/textile_help.rhtml +24 -28
- data/app/views/wiki/authors.rhtml +11 -13
- data/app/views/wiki/edit.rhtml +39 -31
- data/app/views/wiki/export.rhtml +12 -14
- data/app/views/wiki/feeds.rhtml +14 -10
- data/app/views/wiki/list.rhtml +64 -57
- data/app/views/wiki/locked.rhtml +23 -14
- data/app/views/wiki/login.rhtml +14 -11
- data/app/views/wiki/new.rhtml +31 -27
- data/app/views/wiki/page.rhtml +115 -81
- data/app/views/wiki/print.rhtml +14 -16
- data/app/views/wiki/published.rhtml +9 -10
- data/app/views/wiki/recently_revised.rhtml +27 -30
- data/app/views/wiki/revision.rhtml +103 -81
- data/app/views/wiki/rollback.rhtml +14 -9
- data/app/views/wiki/rss_feed.rhtml +22 -22
- data/app/views/wiki/search.rhtml +38 -15
- data/app/views/wiki/tex.rhtml +22 -22
- data/app/views/wiki/tex_web.rhtml +34 -34
- data/app/views/wiki/web_list.rhtml +18 -13
- data/app/views/wiki_words_help.rhtml +9 -8
- data/config/environment.rb +82 -0
- data/config/environments/development.rb +5 -0
- data/config/environments/production.rb +4 -0
- data/config/environments/test.rb +17 -0
- data/config/routes.rb +18 -0
- data/instiki +6 -67
- data/instiki.rb +3 -0
- data/lib/active_record_stub.rb +31 -0
- data/{libraries/diff → lib}/diff.rb +444 -475
- data/lib/instiki_errors.rb +15 -0
- data/{libraries → lib}/rdocsupport.rb +151 -155
- data/lib/redcloth_for_tex.rb +736 -0
- data/natives/osx/desktop_launcher/AppDelegate.h +18 -0
- data/natives/osx/desktop_launcher/AppDelegate.mm +109 -0
- data/natives/osx/desktop_launcher/Credits.html +16 -0
- data/natives/osx/desktop_launcher/English.lproj/InfoPlist.strings +0 -0
- data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/classes.nib +13 -0
- data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/info.nib +24 -0
- data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/objects.nib +0 -0
- data/natives/osx/desktop_launcher/Info.plist +13 -0
- data/natives/osx/desktop_launcher/Instiki.xcode/project.pbxproj +592 -0
- data/natives/osx/desktop_launcher/Instiki_Prefix.pch +7 -0
- data/natives/osx/desktop_launcher/MakeDMG.sh +9 -0
- data/natives/osx/desktop_launcher/main.mm +14 -0
- data/natives/osx/desktop_launcher/version.plist +16 -0
- data/public/404.html +6 -0
- data/public/500.html +6 -0
- data/public/dispatch.rb +10 -0
- data/public/favicon.ico +0 -0
- data/public/javascripts/edit_web.js +52 -0
- data/public/javascripts/prototype.js +336 -0
- data/{app/views/static_style_sheet.rhtml → public/stylesheets/instiki.css} +221 -198
- data/script/breakpointer +4 -0
- data/script/server +93 -0
- metadata +59 -32
- data/app/controllers/wiki.rb +0 -389
- data/app/models/chunks/match.rb +0 -19
- data/app/views/bottom.rhtml +0 -4
- data/app/views/top.rhtml +0 -49
- data/app/views/wiki/edit_web.rhtml +0 -138
- data/libraries/action_controller_servlet.rb +0 -177
- data/libraries/erb.rb +0 -490
- data/libraries/madeleine_service.rb +0 -68
- data/libraries/redcloth_for_tex.rb +0 -869
- data/libraries/web_controller_server.rb +0 -81
data/app/models/chunks/match.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# This module is to be included in unit tests that involve matching chunks.
|
2
|
-
# It provides a easy way to test whether a chunk matches a particular string
|
3
|
-
# and any the values of any fields that should be set after a match.
|
4
|
-
module ChunkMatch
|
5
|
-
|
6
|
-
# Asserts a number of tests for the given type and text.
|
7
|
-
def match(type, test_text, expected)
|
8
|
-
pattern = type.pattern
|
9
|
-
assert_match(pattern, test_text)
|
10
|
-
pattern =~ test_text # Previous assertion guarantees match
|
11
|
-
chunk = type.new($~)
|
12
|
-
|
13
|
-
# Test if requested parts are correct.
|
14
|
-
for method_sym, value in expected do
|
15
|
-
assert_respond_to(chunk, method_sym)
|
16
|
-
assert_equal(value, chunk.method(method_sym).call, "Checking value of '#{method_sym}'")
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/app/views/bottom.rhtml
DELETED
data/app/views/top.rhtml
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<html xmlns="http://www.w3.org/1999/xhtml">
|
3
|
-
<head>
|
4
|
-
<title>
|
5
|
-
<% if @web && @page && @page.name == "HomePage" && %( show published print ).include?(@action_name) %>
|
6
|
-
<%= @web.name %>
|
7
|
-
<% elsif @web %>
|
8
|
-
<%= @title %> in <%= @web.name %>
|
9
|
-
<% else %>
|
10
|
-
<%= @title %>
|
11
|
-
<% end %>
|
12
|
-
</title>
|
13
|
-
|
14
|
-
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
15
|
-
|
16
|
-
<style type="text/css">
|
17
|
-
h1#pageName, .newWikiWord a, a.existingWikiWord, .newWikiWord a:hover, #TextileHelp h3 {
|
18
|
-
color: #<%= @web ? @web.color : "393" %>;
|
19
|
-
}
|
20
|
-
|
21
|
-
#Container, #Content {
|
22
|
-
width: <%= @content_width || "600" %>px;
|
23
|
-
}
|
24
|
-
<%= sub_template("static_style_sheet") if @inline_style %>
|
25
|
-
</style>
|
26
|
-
|
27
|
-
<link rel="Stylesheet" href="../static_style_sheet/" type="text/css" media="screen" />
|
28
|
-
|
29
|
-
<style type="text/css">
|
30
|
-
<%= @style_additions %>
|
31
|
-
<%= @web ? web.additional_style : "" %>
|
32
|
-
</style>
|
33
|
-
</head>
|
34
|
-
<body>
|
35
|
-
<div id="Container">
|
36
|
-
<div id="Content">
|
37
|
-
|
38
|
-
<h1 id="pageName">
|
39
|
-
<% if @web && @page && @page.name == "HomePage" && %( show published print ).include?(@action_name) %>
|
40
|
-
<%= @web.name %>
|
41
|
-
<% elsif @web %>
|
42
|
-
<small><%= @web.name %></small><br />
|
43
|
-
<%= @title %>
|
44
|
-
<% else %>
|
45
|
-
<%= @title %>
|
46
|
-
<% end %>
|
47
|
-
</h1>
|
48
|
-
|
49
|
-
<%= sub_template "navigation" unless @web.nil? || @hide_navigation %>
|
@@ -1,138 +0,0 @@
|
|
1
|
-
<% @title = "Edit Web" %><%= sub_template "top" %>
|
2
|
-
|
3
|
-
<form action="../update_web" id="setup" method="post" onSubmit="cleanAddress(); return validateSetup()">
|
4
|
-
<h2 style="margin-bottom: 3px">Name and address</h2>
|
5
|
-
<div class="help">
|
6
|
-
The name of the web is included in the title on all pages. The address is the base path that all pages within the web live beneath.
|
7
|
-
Ex: the address "rails" gives URLs like <i>/rails/show/HomePage</i>.
|
8
|
-
</div>
|
9
|
-
|
10
|
-
<div class="inputBox">
|
11
|
-
Name: <input type="text" id="name" name="name" value="<%= @web.name %>" onChange="proposeAddress();">
|
12
|
-
Address: <input type="text" id="address" name="address" value="<%= @web.address %>" onChange="cleanAddress();">
|
13
|
-
<i>(Letters & digits only)</i>
|
14
|
-
</div>
|
15
|
-
|
16
|
-
<h2 style="margin-bottom: 3px">Specialize</h2>
|
17
|
-
<div class="help">
|
18
|
-
Turning safe mode on will strip HTML tags and stylesheet options from the content of all pages.
|
19
|
-
Turning on "brackets only" will require all wiki words to be as [[wiki word]] and WikiWord won't work.
|
20
|
-
Additions to the stylesheet take precedence over the existing styles. <i>Hint:</i> View source on a page you want to
|
21
|
-
style to find ID names on individual tags. <a href="#" onClick="document.getElementById('additionalStyle').style.display='block';return false;">See styles >></a>
|
22
|
-
</div>
|
23
|
-
<div class="inputBox">
|
24
|
-
Markup:
|
25
|
-
<select name="markup">
|
26
|
-
<%= html_options({ "Textile" => :textile, "Markdown" => :markdown, "RDoc" => :rdoc }, @web.markup) %>
|
27
|
-
</select>
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
Color:
|
32
|
-
<select name="color">
|
33
|
-
<%= html_options({ "Green" => "008B26", "Purple" => "504685", "Red" => "DA0006", "Orange" => "FA6F00", "Grey" => "8BA2B0" },
|
34
|
-
@web.color) %>
|
35
|
-
</select>
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
<small>
|
40
|
-
|
41
|
-
<input type="checkbox" name="safe_mode"<%= " CHECKED" if @web.safe_mode %>> Safe mode
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
<input type="checkbox" name="brackets_only"<%= " CHECKED" if @web.brackets_only %>> Brackets only
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
<input type="checkbox" name="count_pages"<%= " CHECKED" if @web.count_pages %>> Count pages
|
50
|
-
|
51
|
-
</small>
|
52
|
-
|
53
|
-
<textarea id="additionalStyle" style="display: none; margin-top: 10px; margin-bottom: 5px; width: 560px; height: 200px" name="additional_style"><%= @web.additional_style %></textarea>
|
54
|
-
</div>
|
55
|
-
|
56
|
-
<h2 style="margin-bottom: 3px">Password protection for this web (<%= @web.name %>)</h2>
|
57
|
-
<div class="help">
|
58
|
-
This is the password that visitors need to view and edit this web. Setting the password to nothing will remove the password protection.
|
59
|
-
</div>
|
60
|
-
<div class="inputBox">
|
61
|
-
Password: <input type="password" id="password" name="password" value="<%= @web.password %>">
|
62
|
-
Verify: <input type="password" id="password_check" value="<%= @web.password %>" name="password_check">
|
63
|
-
</div>
|
64
|
-
|
65
|
-
<h2 style="margin-bottom: 3px">Publish read-only version of this web (<%= @web.name %>)</h2>
|
66
|
-
<div class="help">
|
67
|
-
You can turn on a read-only version of this web that's accessible even when the regular web is password protected.
|
68
|
-
The published version is accessible through URLs like /wiki/published/HomePage.
|
69
|
-
</div>
|
70
|
-
<div class="inputBox">
|
71
|
-
<input type="checkbox" name="published"<%= " CHECKED" if @web.published %>> Publish this web
|
72
|
-
</div>
|
73
|
-
|
74
|
-
<p align="right">
|
75
|
-
<small>
|
76
|
-
Enter system password
|
77
|
-
<input type="password" id="system_password" name="system_password">
|
78
|
-
and
|
79
|
-
<input type="submit" value="Update Web">
|
80
|
-
<br/><br/>
|
81
|
-
...or forget changes and <a href="/new_web/">create a new web</a>
|
82
|
-
</small>
|
83
|
-
</p>
|
84
|
-
|
85
|
-
</form>
|
86
|
-
|
87
|
-
<br/>
|
88
|
-
<h1>Other administrative tasks</h1>
|
89
|
-
|
90
|
-
<form action="../remove_orphaned_pages" id="remove_orphaned_pages" method="post">
|
91
|
-
|
92
|
-
<p align="right">
|
93
|
-
<small>
|
94
|
-
Clean up by entering system password
|
95
|
-
<input type="password" id="system_password" name="system_password">
|
96
|
-
and
|
97
|
-
<input type="submit" value="Delete Orphan Pages">
|
98
|
-
</small>
|
99
|
-
</p>
|
100
|
-
|
101
|
-
<script>
|
102
|
-
function proposeAddress() {
|
103
|
-
document.getElementById('address').value =
|
104
|
-
document.getElementById('name').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
|
105
|
-
}
|
106
|
-
|
107
|
-
function cleanAddress() {
|
108
|
-
document.getElementById('address').value =
|
109
|
-
document.getElementById('address').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
|
110
|
-
}
|
111
|
-
|
112
|
-
function validateSetup() {
|
113
|
-
if (document.getElementById('system_password').value == "") {
|
114
|
-
alert("You must enter the system password");
|
115
|
-
return false;
|
116
|
-
}
|
117
|
-
|
118
|
-
if (document.getElementById('name').value == "") {
|
119
|
-
alert("You must pick a name for the web");
|
120
|
-
return false;
|
121
|
-
}
|
122
|
-
|
123
|
-
if (document.getElementById('address').value == "") {
|
124
|
-
alert("You must pick an address for the web");
|
125
|
-
return false;
|
126
|
-
}
|
127
|
-
|
128
|
-
if (document.getElementById('password').value != "" &&
|
129
|
-
document.getElementById('password').value != document.getElementById('password_check').value) {
|
130
|
-
alert("The password and its verification doesn't match");
|
131
|
-
return false;
|
132
|
-
}
|
133
|
-
|
134
|
-
return true;
|
135
|
-
}
|
136
|
-
</script>
|
137
|
-
|
138
|
-
<%= sub_template "bottom" %>
|
@@ -1,177 +0,0 @@
|
|
1
|
-
require 'erb'
|
2
|
-
require 'cgi'
|
3
|
-
require 'webrick'
|
4
|
-
include WEBrick
|
5
|
-
|
6
|
-
require 'view_helper'
|
7
|
-
|
8
|
-
class ActionControllerServlet < HTTPServlet::AbstractServlet
|
9
|
-
@@template_root = "./views"
|
10
|
-
def self.template_root() @@template_root end
|
11
|
-
def self.template_root=(template_root) @@template_root = template_root end
|
12
|
-
|
13
|
-
include ViewHelper
|
14
|
-
|
15
|
-
def do_POST(req, res) do_GET(req, res) end
|
16
|
-
|
17
|
-
def do_GET(req, res)
|
18
|
-
@req, @res = req, res
|
19
|
-
|
20
|
-
@res['Content-Type'] = "text/html; charset=utf-8"
|
21
|
-
@res['Pragma'] = "no-cache"
|
22
|
-
@res['Cache-Control'] = "no-cache"
|
23
|
-
|
24
|
-
@params = @req.query
|
25
|
-
@assigns = {}
|
26
|
-
@performed_render = @performed_redirect = false
|
27
|
-
|
28
|
-
@logger.info "Performing #{action_name}"
|
29
|
-
@logger.info " Parameters: #{@params.inspect}"
|
30
|
-
@logger.info " Cookies: #{@req.cookies.collect { |c| "#{c.name} => #{c.value}" }.join(", ") }"
|
31
|
-
|
32
|
-
perform_action
|
33
|
-
@res
|
34
|
-
end
|
35
|
-
|
36
|
-
protected
|
37
|
-
def template_root() self.class.template_root end
|
38
|
-
|
39
|
-
# Issues a HTTP 302 (location) redirect to the specified <tt>path</tt>. Query string
|
40
|
-
# parameters can be specified in the <tt>params</tt> hash and are automatically URL escaped.
|
41
|
-
# An <tt>anchor</tt> can also be specified (as a string).
|
42
|
-
def redirect_path(path, params = nil, anchor = nil)
|
43
|
-
path << build_query_string(params) unless params.nil?
|
44
|
-
path << "\##{anchor}" unless anchor.nil?
|
45
|
-
@res.set_redirect WEBrick::HTTPStatus::MovedPermanently, path
|
46
|
-
@performed_redirect = true
|
47
|
-
end
|
48
|
-
|
49
|
-
# Redirects the browser to another action within the current controller, so redirect_path "pages"
|
50
|
-
# within a controller called WikiController would take the user to "http://www.example.com/wiki/pages"
|
51
|
-
def redirect_action(action, params = nil, anchor = nil)
|
52
|
-
redirect_path "/#{controller_name}/#{action}", params, anchor
|
53
|
-
end
|
54
|
-
|
55
|
-
|
56
|
-
# Compiles the template response and adds it to the response. If no template_name has been
|
57
|
-
# supplied, the action parameter parsed to the controller is used. So invoking
|
58
|
-
# render on a object initialized with myController.new("show_person") will compile the template
|
59
|
-
# located at "../views/show_person.rhtml". Notice that the ".rhtml" extension is postfixed
|
60
|
-
# to the template_name regardless of one was passed or that the action parameter was used.
|
61
|
-
def render(template_name = "#{controller_name}/#{action_name}")
|
62
|
-
@performed_render = true
|
63
|
-
@logger.info "Rendering: #{template_name}"
|
64
|
-
add_instance_variables_to_assigns
|
65
|
-
@res.body = template_result "#{template_root}/#{template_name}.rhtml"
|
66
|
-
end
|
67
|
-
|
68
|
-
def render_text(text)
|
69
|
-
@performed_render = true
|
70
|
-
@logger.info "Rendering in text"
|
71
|
-
@res.body = text
|
72
|
-
end
|
73
|
-
|
74
|
-
# Wrapper around render that presumes the current controller is used as a base for the action,
|
75
|
-
# so render_action("page") in WikiController will be equal to render("wiki/page")
|
76
|
-
def render_action(action_name)
|
77
|
-
render "#{controller_name}/#{action_name}"
|
78
|
-
end
|
79
|
-
|
80
|
-
def sub_template(template_name)
|
81
|
-
template_result "#{template_root}/#{template_name}.rhtml"
|
82
|
-
end
|
83
|
-
|
84
|
-
# Returns the value of the cookie matching +name+ (or nil if none is found).
|
85
|
-
def read_cookie(key)
|
86
|
-
cookies = @req.cookies.select { |cookie| cookie.name == key }
|
87
|
-
cookies.empty? ? nil : cookies.first.value
|
88
|
-
end
|
89
|
-
|
90
|
-
def write_cookie(key, value, permanent = false)
|
91
|
-
@logger.info "Writing cookie: #{key} => #{value}"
|
92
|
-
|
93
|
-
cookie = WEBrick::Cookie.new(key, value)
|
94
|
-
cookie.path = "/"
|
95
|
-
cookie.expires = Time.local(2030) if permanent
|
96
|
-
@res.cookies << cookie
|
97
|
-
end
|
98
|
-
|
99
|
-
|
100
|
-
# Returns the last part of the uri path ("page" in "/wiki/page") by default, but
|
101
|
-
# can be overwritten to implement mod_rewrite-like behaviour, such as "page" in "/wiki/page/home"
|
102
|
-
def action_name
|
103
|
-
@req.path.to_s.split(/\//).last
|
104
|
-
end
|
105
|
-
|
106
|
-
# Returns an array with each of the parts in the request as an element. So /something/cool/dude
|
107
|
-
# returns ["something", "cool", "dude"]
|
108
|
-
def request_path
|
109
|
-
request_path_parts = @req.path.to_s.split(/\//)
|
110
|
-
request_path_parts.length > 1 ? request_path_parts[1..-1] : []
|
111
|
-
end
|
112
|
-
|
113
|
-
# Can be overwritten by a controller class to implement shared behaviour for all the actions in
|
114
|
-
# the class, such as security measures
|
115
|
-
def before_action() end
|
116
|
-
|
117
|
-
|
118
|
-
private
|
119
|
-
# Wraps around all action calls to ensure the session is properly updated and closed.
|
120
|
-
# Figures out whether an action, such as "list", is implemented as show_list or do_list.
|
121
|
-
# The show_* type has precedence and automatically calls render after execution.
|
122
|
-
def perform_action
|
123
|
-
if before_action == false then return end
|
124
|
-
|
125
|
-
if action_methods.include?(action_name)
|
126
|
-
send(action_name)
|
127
|
-
render unless @performed_render || @performed_redirect || !@res.body.empty?
|
128
|
-
elsif template_exists_for_action
|
129
|
-
render
|
130
|
-
else
|
131
|
-
raise "No action responded to #{action_name}", caller
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def add_instance_variables_to_assigns
|
136
|
-
instance_variables.each { |var|
|
137
|
-
next if protected_instance_variables.include?(var)
|
138
|
-
@assigns[var[1..-1]] = instance_variable_get(var)
|
139
|
-
}
|
140
|
-
end
|
141
|
-
|
142
|
-
def protected_instance_variables
|
143
|
-
[ "@assigns", "@performed_redirect", "@performed_render" ]
|
144
|
-
end
|
145
|
-
|
146
|
-
def action_methods
|
147
|
-
methods - Object.instance_methods
|
148
|
-
end
|
149
|
-
|
150
|
-
# Returns true if a template exists in the controller directory for the specified <tt>action_name</tt>,
|
151
|
-
# which would mean true if called for WikiController#changes and "/views/wiki/changes.rhtml" existed.
|
152
|
-
def template_exists_for_action
|
153
|
-
File.exist? action_template_path
|
154
|
-
end
|
155
|
-
|
156
|
-
def action_template_path(action = action_name)
|
157
|
-
"#{template_root}/#{controller_name}/#{action}.rhtml"
|
158
|
-
end
|
159
|
-
|
160
|
-
def template_result(template_path)
|
161
|
-
@assigns.each { |key, value| instance_variable_set "@#{key}", value }
|
162
|
-
ERB.new(IO.readlines(template_path).join).result(binding)
|
163
|
-
end
|
164
|
-
|
165
|
-
# Converts the class name from something like "OneModule::TwoModule::NeatController"
|
166
|
-
# to "neat".
|
167
|
-
def controller_name
|
168
|
-
self.class.to_s.split("::").last.sub(/Controller/, "").downcase
|
169
|
-
end
|
170
|
-
|
171
|
-
# Returns a query string with escaped keys and values from the passed hash.
|
172
|
-
def build_query_string(hash)
|
173
|
-
elements = []
|
174
|
-
hash.each { |key, value| elements << "#{CGI.escape(key)}=#{CGI.escape(value.to_s)}" }
|
175
|
-
"?" + elements.join("&")
|
176
|
-
end
|
177
|
-
end
|
data/libraries/erb.rb
DELETED
@@ -1,490 +0,0 @@
|
|
1
|
-
# Tiny eRuby --- ERB2
|
2
|
-
# Copyright (c) 1999-2000,2002,2003 Masatoshi SEKI
|
3
|
-
# You can redistribute it and/or modify it under the same terms as Ruby.
|
4
|
-
|
5
|
-
class ERB
|
6
|
-
Revision = '$Date: 2004/02/23 23:40:09 $' #'
|
7
|
-
|
8
|
-
def self.version
|
9
|
-
"erb.rb [2.0.4 #{ERB::Revision.split[1]}]"
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
# ERB::Compiler
|
14
|
-
class ERB
|
15
|
-
class Compiler
|
16
|
-
class PercentLine
|
17
|
-
def initialize(str)
|
18
|
-
@value = str
|
19
|
-
end
|
20
|
-
attr_reader :value
|
21
|
-
alias :to_s :value
|
22
|
-
end
|
23
|
-
|
24
|
-
class Scanner
|
25
|
-
SplitRegexp = /(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>)|(\n)/
|
26
|
-
|
27
|
-
@scanner_map = {}
|
28
|
-
def self.regist_scanner(klass, trim_mode, percent)
|
29
|
-
@scanner_map[[trim_mode, percent]] = klass
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.default_scanner=(klass)
|
33
|
-
@default_scanner = klass
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.make_scanner(src, trim_mode, percent)
|
37
|
-
klass = @scanner_map.fetch([trim_mode, percent], @default_scanner)
|
38
|
-
klass.new(src, trim_mode, percent)
|
39
|
-
end
|
40
|
-
|
41
|
-
def initialize(src, trim_mode, percent)
|
42
|
-
@src = src
|
43
|
-
@stag = nil
|
44
|
-
end
|
45
|
-
attr_accessor :stag
|
46
|
-
|
47
|
-
def scan; end
|
48
|
-
end
|
49
|
-
|
50
|
-
class TrimScanner < Scanner
|
51
|
-
TrimSplitRegexp = /(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>\n)|(%>)|(\n)/
|
52
|
-
|
53
|
-
def initialize(src, trim_mode, percent)
|
54
|
-
super
|
55
|
-
@trim_mode = trim_mode
|
56
|
-
@percent = percent
|
57
|
-
if @trim_mode == '>'
|
58
|
-
@scan_line = self.method(:trim_line1)
|
59
|
-
elsif @trim_mode == '<>'
|
60
|
-
@scan_line = self.method(:trim_line2)
|
61
|
-
elsif @trim_mode == '-'
|
62
|
-
@scan_line = self.method(:explicit_trim_line)
|
63
|
-
else
|
64
|
-
@scan_line = self.method(:scan_line)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
attr_accessor :stag
|
68
|
-
|
69
|
-
def scan(&block)
|
70
|
-
@stag = nil
|
71
|
-
if @percent
|
72
|
-
@src.each do |line|
|
73
|
-
percent_line(line, &block)
|
74
|
-
end
|
75
|
-
else
|
76
|
-
@src.each do |line|
|
77
|
-
@scan_line.call(line, &block)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
nil
|
81
|
-
end
|
82
|
-
|
83
|
-
def percent_line(line, &block)
|
84
|
-
if @stag || line[0] != ?%
|
85
|
-
return @scan_line.call(line, &block)
|
86
|
-
end
|
87
|
-
|
88
|
-
line[0] = ''
|
89
|
-
if line[0] == ?%
|
90
|
-
@scan_line.call(line, &block)
|
91
|
-
else
|
92
|
-
yield(PercentLine.new(line.chomp))
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def scan_line(line)
|
97
|
-
line.split(SplitRegexp).each do |token|
|
98
|
-
next if token.empty?
|
99
|
-
yield(token)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def trim_line1(line)
|
104
|
-
line.split(TrimSplitRegexp).each do |token|
|
105
|
-
next if token.empty?
|
106
|
-
if token == "%>\n"
|
107
|
-
yield('%>')
|
108
|
-
yield(:cr)
|
109
|
-
break
|
110
|
-
end
|
111
|
-
yield(token)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def trim_line2(line)
|
116
|
-
head = nil
|
117
|
-
line.split(TrimSplitRegexp).each do |token|
|
118
|
-
next if token.empty?
|
119
|
-
head = token unless head
|
120
|
-
if token == "%>\n"
|
121
|
-
yield('%>')
|
122
|
-
if is_erb_stag?(head)
|
123
|
-
yield(:cr)
|
124
|
-
else
|
125
|
-
yield("\n")
|
126
|
-
end
|
127
|
-
break
|
128
|
-
end
|
129
|
-
yield(token)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
ExplicitTrimRegexp = /(^[ \t]*<%-)|(-%>\n?\z)|(<%-)|(-%>)|(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>)|(\n)/
|
134
|
-
def explicit_trim_line(line)
|
135
|
-
line.split(ExplicitTrimRegexp).each do |token|
|
136
|
-
next if token.empty?
|
137
|
-
if @stag.nil? && /[ \t]*<%-/ =~ token
|
138
|
-
yield('<%')
|
139
|
-
elsif @stag && /-%>\n/ =~ token
|
140
|
-
yield('%>')
|
141
|
-
yield(:cr)
|
142
|
-
elsif @stag && token == '-%>'
|
143
|
-
yield('%>')
|
144
|
-
else
|
145
|
-
yield(token)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
ERB_STAG = %w(<%= <%# <%)
|
151
|
-
def is_erb_stag?(s)
|
152
|
-
ERB_STAG.member?(s)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
Scanner.default_scanner = TrimScanner
|
157
|
-
|
158
|
-
class SimpleScanner < Scanner
|
159
|
-
def scan
|
160
|
-
@src.each do |line|
|
161
|
-
line.split(SplitRegexp).each do |token|
|
162
|
-
next if token.empty?
|
163
|
-
yield(token)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
Scanner.regist_scanner(SimpleScanner, nil, false)
|
170
|
-
|
171
|
-
begin
|
172
|
-
require 'strscan'
|
173
|
-
class SimpleScanner2 < Scanner
|
174
|
-
def scan
|
175
|
-
stag_reg = /(.*?)(<%%|<%=|<%#|<%|\n|\z)/
|
176
|
-
etag_reg = /(.*?)(%%>|%>|\n|\z)/
|
177
|
-
scanner = StringScanner.new(@src)
|
178
|
-
while ! scanner.eos?
|
179
|
-
scanner.scan(@stag ? etag_reg : stag_reg)
|
180
|
-
text = scanner[1]
|
181
|
-
elem = scanner[2]
|
182
|
-
yield(text) unless text.empty?
|
183
|
-
yield(elem) unless elem.empty?
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
Scanner.regist_scanner(SimpleScanner2, nil, false)
|
188
|
-
|
189
|
-
class PercentScanner < Scanner
|
190
|
-
def scan
|
191
|
-
new_line = true
|
192
|
-
stag_reg = /(.*?)(<%%|<%=|<%#|<%|\n|\z)/
|
193
|
-
etag_reg = /(.*?)(%%>|%>|\n|\z)/
|
194
|
-
scanner = StringScanner.new(@src)
|
195
|
-
while ! scanner.eos?
|
196
|
-
if new_line && @stag.nil?
|
197
|
-
if scanner.scan(/%%/)
|
198
|
-
yield('%')
|
199
|
-
new_line = false
|
200
|
-
next
|
201
|
-
elsif scanner.scan(/%/)
|
202
|
-
yield(PercentLine.new(scanner.scan(/.*?(\n|\z)/).chomp))
|
203
|
-
next
|
204
|
-
end
|
205
|
-
end
|
206
|
-
scanner.scan(@stag ? etag_reg : stag_reg)
|
207
|
-
text = scanner[1]
|
208
|
-
elem = scanner[2]
|
209
|
-
yield(text) unless text.empty?
|
210
|
-
yield(elem) unless elem.empty?
|
211
|
-
new_line = (elem == "\n")
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
215
|
-
Scanner.regist_scanner(PercentScanner, nil, true)
|
216
|
-
|
217
|
-
class ExplicitScanner < Scanner
|
218
|
-
def scan
|
219
|
-
new_line = true
|
220
|
-
stag_reg = /(.*?)(<%%|<%=|<%#|<%-|<%|\n|\z)/
|
221
|
-
etag_reg = /(.*?)(%%>|-%>|%>|\n|\z)/
|
222
|
-
scanner = StringScanner.new(@src)
|
223
|
-
while ! scanner.eos?
|
224
|
-
if new_line && @stag.nil? && scanner.scan(/[ \t]*<%-/)
|
225
|
-
yield('<%')
|
226
|
-
new_line = false
|
227
|
-
next
|
228
|
-
end
|
229
|
-
scanner.scan(@stag ? etag_reg : stag_reg)
|
230
|
-
text = scanner[1]
|
231
|
-
elem = scanner[2]
|
232
|
-
new_line = (elem == "\n")
|
233
|
-
yield(text) unless text.empty?
|
234
|
-
if elem == '-%>'
|
235
|
-
yield('%>')
|
236
|
-
if scanner.scan(/(\n|\z)/)
|
237
|
-
yield(:cr)
|
238
|
-
new_line = true
|
239
|
-
end
|
240
|
-
elsif elem == '<%-'
|
241
|
-
yield('<%')
|
242
|
-
else
|
243
|
-
yield(elem) unless elem.empty?
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
248
|
-
Scanner.regist_scanner(ExplicitScanner, '-', false)
|
249
|
-
|
250
|
-
rescue LoadError
|
251
|
-
end
|
252
|
-
|
253
|
-
class Buffer
|
254
|
-
def initialize(compiler)
|
255
|
-
@compiler = compiler
|
256
|
-
@line = []
|
257
|
-
@script = ''
|
258
|
-
@compiler.pre_cmd.each do |x|
|
259
|
-
push(x)
|
260
|
-
end
|
261
|
-
end
|
262
|
-
attr_reader :script
|
263
|
-
|
264
|
-
def push(cmd)
|
265
|
-
@line << cmd
|
266
|
-
end
|
267
|
-
|
268
|
-
def cr
|
269
|
-
@script << (@line.join('; '))
|
270
|
-
@line = []
|
271
|
-
@script << "\n"
|
272
|
-
end
|
273
|
-
|
274
|
-
def close
|
275
|
-
return unless @line
|
276
|
-
@compiler.post_cmd.each do |x|
|
277
|
-
push(x)
|
278
|
-
end
|
279
|
-
@script << (@line.join('; '))
|
280
|
-
@line = nil
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
class Buffer16 < Buffer
|
285
|
-
def initialize(compiler)
|
286
|
-
super(compiler)
|
287
|
-
@script = []
|
288
|
-
end
|
289
|
-
|
290
|
-
def script
|
291
|
-
@script.join('')
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
def make_buffer
|
296
|
-
if RUBY_VERSION > '1.8'
|
297
|
-
Buffer.new(self)
|
298
|
-
else
|
299
|
-
Buffer16.new(self)
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
def compile(s)
|
304
|
-
out = make_buffer
|
305
|
-
|
306
|
-
content = ''
|
307
|
-
scanner = make_scanner(s)
|
308
|
-
scanner.scan do |token|
|
309
|
-
if scanner.stag.nil?
|
310
|
-
case token
|
311
|
-
when PercentLine
|
312
|
-
out.push("#{@put_cmd} #{content.dump}") if content.size > 0
|
313
|
-
content = ''
|
314
|
-
out.push(token.to_s)
|
315
|
-
out.cr
|
316
|
-
when :cr
|
317
|
-
out.cr
|
318
|
-
when '<%', '<%=', '<%#'
|
319
|
-
scanner.stag = token
|
320
|
-
out.push("#{@put_cmd} #{content.dump}") if content.size > 0
|
321
|
-
content = ''
|
322
|
-
when "\n"
|
323
|
-
content << "\n"
|
324
|
-
out.push("#{@put_cmd} #{content.dump}")
|
325
|
-
out.cr
|
326
|
-
content = ''
|
327
|
-
when '<%%'
|
328
|
-
content << '<%'
|
329
|
-
else
|
330
|
-
content << token
|
331
|
-
end
|
332
|
-
else
|
333
|
-
case token
|
334
|
-
when '%>'
|
335
|
-
case scanner.stag
|
336
|
-
when '<%'
|
337
|
-
if content[-1] == ?\n
|
338
|
-
content.chop!
|
339
|
-
out.push(content)
|
340
|
-
out.cr
|
341
|
-
else
|
342
|
-
out.push(content)
|
343
|
-
end
|
344
|
-
when '<%='
|
345
|
-
out.push("#{@put_cmd}((#{content}).to_s)")
|
346
|
-
when '<%#'
|
347
|
-
# out.push("# #{content.dump}")
|
348
|
-
end
|
349
|
-
scanner.stag = nil
|
350
|
-
content = ''
|
351
|
-
when '%%>'
|
352
|
-
content << '%>'
|
353
|
-
else
|
354
|
-
content << token
|
355
|
-
end
|
356
|
-
end
|
357
|
-
end
|
358
|
-
out.push("#{@put_cmd} #{content.dump}") if content.size > 0
|
359
|
-
out.close
|
360
|
-
out.script
|
361
|
-
end
|
362
|
-
|
363
|
-
def prepare_trim_mode(mode)
|
364
|
-
case mode
|
365
|
-
when 1
|
366
|
-
return [false, '>']
|
367
|
-
when 2
|
368
|
-
return [false, '<>']
|
369
|
-
when 0
|
370
|
-
return [false, nil]
|
371
|
-
when String
|
372
|
-
perc = mode.include?('%')
|
373
|
-
if mode.include?('-')
|
374
|
-
return [perc, '-']
|
375
|
-
elsif mode.include?('<>')
|
376
|
-
return [perc, '<>']
|
377
|
-
elsif mode.include?('>')
|
378
|
-
return [perc, '>']
|
379
|
-
else
|
380
|
-
[perc, nil]
|
381
|
-
end
|
382
|
-
else
|
383
|
-
return [false, nil]
|
384
|
-
end
|
385
|
-
end
|
386
|
-
|
387
|
-
def make_scanner(src)
|
388
|
-
Scanner.make_scanner(src, @trim_mode, @percent)
|
389
|
-
end
|
390
|
-
|
391
|
-
def initialize(trim_mode)
|
392
|
-
@percent, @trim_mode = prepare_trim_mode(trim_mode)
|
393
|
-
@put_cmd = 'print'
|
394
|
-
@pre_cmd = []
|
395
|
-
@post_cmd = []
|
396
|
-
end
|
397
|
-
attr_reader :percent, :trim_mode
|
398
|
-
attr_accessor :put_cmd, :pre_cmd, :post_cmd
|
399
|
-
end
|
400
|
-
end
|
401
|
-
|
402
|
-
# ERB
|
403
|
-
class ERB
|
404
|
-
def initialize(str, safe_level=nil, trim_mode=nil, eoutvar='_erbout')
|
405
|
-
@safe_level = safe_level
|
406
|
-
compiler = ERB::Compiler.new(trim_mode)
|
407
|
-
set_eoutvar(compiler, eoutvar)
|
408
|
-
@src = compiler.compile(str)
|
409
|
-
end
|
410
|
-
attr :src
|
411
|
-
|
412
|
-
def set_eoutvar(compiler, eoutvar = '_erbout')
|
413
|
-
compiler.put_cmd = "#{eoutvar}.concat"
|
414
|
-
|
415
|
-
cmd = []
|
416
|
-
cmd.push "#{eoutvar} = ''"
|
417
|
-
|
418
|
-
compiler.pre_cmd = cmd
|
419
|
-
|
420
|
-
cmd = []
|
421
|
-
cmd.push(eoutvar)
|
422
|
-
|
423
|
-
compiler.post_cmd = cmd
|
424
|
-
end
|
425
|
-
|
426
|
-
def run(b=TOPLEVEL_BINDING)
|
427
|
-
print self.result(b)
|
428
|
-
end
|
429
|
-
|
430
|
-
def result(b=TOPLEVEL_BINDING)
|
431
|
-
if @safe_level
|
432
|
-
th = Thread.start {
|
433
|
-
$SAFE = @safe_level
|
434
|
-
eval(@src, b)
|
435
|
-
}
|
436
|
-
return th.value
|
437
|
-
else
|
438
|
-
return eval(@src, b)
|
439
|
-
end
|
440
|
-
end
|
441
|
-
|
442
|
-
def def_method(mod, methodname, fname='(ERB)')
|
443
|
-
mod.module_eval("def #{methodname}\n" + self.src + "\nend\n", fname, 0)
|
444
|
-
end
|
445
|
-
|
446
|
-
def def_module(methodname='erb')
|
447
|
-
mod = Module.new
|
448
|
-
def_method(mod, methodname)
|
449
|
-
mod
|
450
|
-
end
|
451
|
-
|
452
|
-
def def_class(superklass=Object, methodname='result')
|
453
|
-
cls = Class.new(superklass)
|
454
|
-
def_method(cls, methodname)
|
455
|
-
cls
|
456
|
-
end
|
457
|
-
end
|
458
|
-
|
459
|
-
# ERB::Util
|
460
|
-
class ERB
|
461
|
-
module Util
|
462
|
-
public
|
463
|
-
def html_escape(s)
|
464
|
-
s.to_s.gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/</, "<")
|
465
|
-
end
|
466
|
-
alias h html_escape
|
467
|
-
|
468
|
-
def url_encode(s)
|
469
|
-
s.to_s.gsub(/[^a-zA-Z0-9_\-.]/n){ sprintf("%%%02X", $&.unpack("C")[0]) }
|
470
|
-
end
|
471
|
-
alias u url_encode
|
472
|
-
end
|
473
|
-
end
|
474
|
-
|
475
|
-
# ERB::DefMethod
|
476
|
-
class ERB
|
477
|
-
module DefMethod
|
478
|
-
public
|
479
|
-
def def_erb_method(methodname, erb)
|
480
|
-
if erb.kind_of? String
|
481
|
-
fname = erb
|
482
|
-
File.open(fname) {|f| erb = ERB.new(f.read) }
|
483
|
-
erb.def_method(self, methodname, fname)
|
484
|
-
else
|
485
|
-
erb.def_method(self, methodname)
|
486
|
-
end
|
487
|
-
end
|
488
|
-
module_function :def_erb_method
|
489
|
-
end
|
490
|
-
end
|