kiss 0.9
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/LICENSE +19 -0
- data/Rakefile +33 -0
- data/VERSION +1 -0
- data/lib/kiss/action.rb +204 -0
- data/lib/kiss/controller_accessors.rb +101 -0
- data/lib/kiss/exception_report.rb +359 -0
- data/lib/kiss/form/field.rb +296 -0
- data/lib/kiss/form.rb +414 -0
- data/lib/kiss/format.rb +80 -0
- data/lib/kiss/hacks.rb +140 -0
- data/lib/kiss/iterator.rb +56 -0
- data/lib/kiss/mailer.rb +92 -0
- data/lib/kiss/model.rb +114 -0
- data/lib/kiss/rack/bench.rb +131 -0
- data/lib/kiss/rack/email_errors.rb +64 -0
- data/lib/kiss/rack/facebook.rb +28 -0
- data/lib/kiss/rack/file_not_found.rb +42 -0
- data/lib/kiss/rack/log_exceptions.rb +23 -0
- data/lib/kiss/rack/show_debug.rb +82 -0
- data/lib/kiss/rack/show_exceptions.rb +27 -0
- data/lib/kiss/sequel_mysql.rb +23 -0
- data/lib/kiss/sequel_session.rb +166 -0
- data/lib/kiss/template_methods.rb +125 -0
- data/lib/kiss.rb +725 -0
- metadata +108 -0
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2005-2008 MultiWidget LLC.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
Gem::manage_gems
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
|
5
|
+
spec = Gem::Specification.new do |s|
|
6
|
+
s.platform = Gem::Platform::RUBY
|
7
|
+
s.name = 'kiss'
|
8
|
+
s.version = File.read('VERSION').chomp
|
9
|
+
s.author = 'Shawn Van Ittersum'
|
10
|
+
s.email = 'shawn @nospam@ multiwidget.com'
|
11
|
+
s.homepage = 'http://www.rubykiss.org'
|
12
|
+
s.rubyforge_project = 'kiss'
|
13
|
+
s.summary = 'An MVC web application framework using Rack, Sequel, and Erubis.'
|
14
|
+
s.files = %w( Rakefile VERSION LICENSE ) + Dir['{lib,tests}/**/*']
|
15
|
+
s.require_path = 'lib'
|
16
|
+
s.test_files = Dir.glob('tests/*.rb')
|
17
|
+
s.has_rdoc = true
|
18
|
+
|
19
|
+
s.rdoc_options << '--main' << 'Kiss' <<
|
20
|
+
'--title' << 'Kiss: Ruby MVC Web Framework -- RDoc Reference Documentation'
|
21
|
+
|
22
|
+
s.add_dependency('rack')
|
23
|
+
s.add_dependency('sequel','>=2.2.0')
|
24
|
+
s.add_dependency('erubis')
|
25
|
+
end
|
26
|
+
|
27
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
28
|
+
pkg.need_tar = true
|
29
|
+
end
|
30
|
+
|
31
|
+
task :default => "pkg/#{spec.name}-#{spec.version}.gem" do
|
32
|
+
puts "generated pkg/#{spec.name}-#{spec.version}.gem"
|
33
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.9
|
data/lib/kiss/action.rb
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
class Kiss
|
2
|
+
class Action
|
3
|
+
include Kiss::TemplateMethods
|
4
|
+
|
5
|
+
# Class Methods
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# Sets reference back to controller (Kiss instance).
|
9
|
+
def set_controller(controller)
|
10
|
+
@@controller = controller
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Instance Methods
|
15
|
+
|
16
|
+
# Raises custom error message for missing methods, specifying current action
|
17
|
+
# more clearly than standard error message.
|
18
|
+
def method_missing(meth)
|
19
|
+
raise NoMethodError, "undefined method `#{meth}' for action `#{@action}'"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Creates a new action instance from controller data.
|
23
|
+
def initialize
|
24
|
+
@action = @@controller.action
|
25
|
+
|
26
|
+
@data = {}
|
27
|
+
@forms = {}
|
28
|
+
@template_dir = @@controller.template_dir
|
29
|
+
end
|
30
|
+
|
31
|
+
# Invokes controller's file_cache, setting exception class to Kiss::TemplateFileNotFound,
|
32
|
+
# which will be raised if file is not found. (This exception class may be caught and
|
33
|
+
# handled by Rack builder option FileNotFound to produce an HTTP 404 error response.)
|
34
|
+
def file_cache(path,fnf_file_type,fnf_exception_class = Kiss::TemplateFileNotFound,&block)
|
35
|
+
controller.file_cache(path,fnf_file_type,fnf_exception_class,&block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def controller
|
39
|
+
@@controller
|
40
|
+
end
|
41
|
+
|
42
|
+
def forms
|
43
|
+
@forms
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns true is `form' param matches current action path.
|
47
|
+
def form_action_match
|
48
|
+
form = params['form']
|
49
|
+
return false unless form =~ /^\w+(\/\w+)*$/s
|
50
|
+
return form == @action || @action =~ /\/#{form}/
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns object from specified table, with id matching first argument (or argument of specified index).
|
54
|
+
def arg_object(table,index = 0)
|
55
|
+
result = dbm[table][arg(index)]
|
56
|
+
raise "#{table.to_s.singularize} not found" unless result
|
57
|
+
|
58
|
+
result
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns arg_object, or new object of specified table if arg_object is not found.
|
62
|
+
def arg_object_or_new(table,*args)
|
63
|
+
return (arg_object(table,*args) ) rescue dbm[table].new
|
64
|
+
end
|
65
|
+
|
66
|
+
# Validates param of specified key against specified format.
|
67
|
+
def validate_param(key, format, required = false)
|
68
|
+
value = @params[key]
|
69
|
+
print_key = key.gsub('_',' ')
|
70
|
+
|
71
|
+
case (Kiss.validate_value(value, format, required))
|
72
|
+
when :missing:
|
73
|
+
raise "required param '#{key}' is missing"
|
74
|
+
when :invalid:
|
75
|
+
raise "param '#{key}' is invalid"
|
76
|
+
end
|
77
|
+
|
78
|
+
value
|
79
|
+
end
|
80
|
+
|
81
|
+
# Validates argument of specified index against specified format.
|
82
|
+
def validate_arg(index, options)
|
83
|
+
value = @args[index]
|
84
|
+
|
85
|
+
case (Kiss.validate_value(value, format, required))
|
86
|
+
when :missing:
|
87
|
+
raise "required arg #{index} is missing"
|
88
|
+
when :invalid:
|
89
|
+
raise "arg #{index} is invalid"
|
90
|
+
end
|
91
|
+
|
92
|
+
value
|
93
|
+
end
|
94
|
+
|
95
|
+
# Creates and invokes new Kiss::Mailer instance to send email message via sendmail.
|
96
|
+
def sendmail(options)
|
97
|
+
Kiss::Mailer.new.sendmail({
|
98
|
+
:data => data
|
99
|
+
}.merge(options))
|
100
|
+
end
|
101
|
+
|
102
|
+
# Creates and invokes new Kiss::Mailer instance to send email message via SMTP,
|
103
|
+
# unless options specify :engine => :sendmail.
|
104
|
+
def send_email(options)
|
105
|
+
controller.new_email.send({
|
106
|
+
:data => data
|
107
|
+
}.merge(options))
|
108
|
+
end
|
109
|
+
|
110
|
+
# Sends HTTP 302 response to redirect client agent to specified URL.
|
111
|
+
def redirect_url(*args)
|
112
|
+
controller.redirect_url(*args)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Redirects to specified action path, which may also include arguments.
|
116
|
+
def redirect_action(action)
|
117
|
+
redirect_url "#{app}#{ app_absolute_path(action) }"
|
118
|
+
end
|
119
|
+
|
120
|
+
# Convert specified action path by prefixing current action_subdir,
|
121
|
+
# unless specified path starts with slash (/).
|
122
|
+
def app_absolute_path(path)
|
123
|
+
debug path
|
124
|
+
path = controller.action_subdir + '/' + path if path !~ /\A\//
|
125
|
+
path
|
126
|
+
end
|
127
|
+
|
128
|
+
# Return string result from rendering specified string or template options.
|
129
|
+
def render_to_string(options)
|
130
|
+
if options.is_a?(String)
|
131
|
+
return options
|
132
|
+
elsif options[:text]
|
133
|
+
return options[:text].to_s
|
134
|
+
end
|
135
|
+
|
136
|
+
@base_url ||= app(action_subdir + '/')
|
137
|
+
@layout = options.is_a?(Hash) && options.has_key?(:layout) ? options[:layout] : "/_layout"
|
138
|
+
|
139
|
+
content = options[:content].is_a?(String) ? options[:content] : process({
|
140
|
+
:template => action,
|
141
|
+
:extension => extension
|
142
|
+
}.merge(options))
|
143
|
+
|
144
|
+
while @layout
|
145
|
+
layout_path = get_template_path(
|
146
|
+
:template => @layout,
|
147
|
+
:extension => options[:extension] || extension
|
148
|
+
) rescue break
|
149
|
+
|
150
|
+
# clear layout
|
151
|
+
# (however, layout template is allowed to set @layout to something else)
|
152
|
+
@layout = nil
|
153
|
+
|
154
|
+
# process layout file
|
155
|
+
content = erubis(layout_path,binding,content)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Kiss 0.9: action parser now redirects into directories (with trailing slash)
|
159
|
+
# don't need to add base tag anymore
|
160
|
+
#content.sub(/(\<html)/i,%Q(<base href="#{@base_url}" />\\1))
|
161
|
+
content
|
162
|
+
end
|
163
|
+
|
164
|
+
# Render and return response to Rack.
|
165
|
+
def render(options = {})
|
166
|
+
output = render_to_string(options)
|
167
|
+
controller.send_response(output,options)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Placeholder for generic actions that do nothing but render template.
|
171
|
+
# render is called from Kiss#call after this method returns.
|
172
|
+
def call; end
|
173
|
+
|
174
|
+
# Creates and adds form to current action, using specified attributes.
|
175
|
+
def add_form(attrs = {})
|
176
|
+
# make sure form not already defined for this request
|
177
|
+
@forms ||= {}
|
178
|
+
attrs[:name] ||= @action
|
179
|
+
form_name = attrs[:name]
|
180
|
+
raise "page contains multiple forms named '#{form_name}'" if @forms.has_key?(form_name)
|
181
|
+
|
182
|
+
# create form
|
183
|
+
uri = app + request.path_info
|
184
|
+
@forms[form_name] = @form = Kiss::Form.new({
|
185
|
+
:action => uri,
|
186
|
+
:request => self
|
187
|
+
}.merge(attrs))
|
188
|
+
|
189
|
+
# add data from controller to form
|
190
|
+
if params['form'] == @form.name
|
191
|
+
@form.submitted = true
|
192
|
+
@form.params = params
|
193
|
+
end
|
194
|
+
|
195
|
+
return @form
|
196
|
+
end
|
197
|
+
|
198
|
+
# Returns most recently added form.
|
199
|
+
# Shorthand for forms[0] when there is only one form.
|
200
|
+
def form
|
201
|
+
@form
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
class Kiss
|
2
|
+
module ControllerAccessors
|
3
|
+
def environment
|
4
|
+
controller.environment
|
5
|
+
end
|
6
|
+
|
7
|
+
def params
|
8
|
+
controller.params
|
9
|
+
end
|
10
|
+
|
11
|
+
def args
|
12
|
+
controller.args
|
13
|
+
end
|
14
|
+
|
15
|
+
def session
|
16
|
+
controller.session
|
17
|
+
end
|
18
|
+
|
19
|
+
def login
|
20
|
+
controller.login
|
21
|
+
end
|
22
|
+
|
23
|
+
def request
|
24
|
+
controller.request
|
25
|
+
end
|
26
|
+
|
27
|
+
def pub(*args)
|
28
|
+
controller.pub(*args)
|
29
|
+
end
|
30
|
+
|
31
|
+
def set_login_expires(*args)
|
32
|
+
controller.set_login_expires(*args)
|
33
|
+
end
|
34
|
+
|
35
|
+
def set_login_data(*args)
|
36
|
+
controller.set_login_data(*args)
|
37
|
+
end
|
38
|
+
|
39
|
+
def set_login_session(*args)
|
40
|
+
controller.set_login_session(*args)
|
41
|
+
end
|
42
|
+
|
43
|
+
def reset_login_data
|
44
|
+
controller.reset_login_data
|
45
|
+
end
|
46
|
+
|
47
|
+
def reset_login_session
|
48
|
+
controller.reset_login_session
|
49
|
+
end
|
50
|
+
|
51
|
+
def login_session_valid?
|
52
|
+
controller.login_session_valid?
|
53
|
+
end
|
54
|
+
|
55
|
+
def db
|
56
|
+
controller.db
|
57
|
+
end
|
58
|
+
alias_method :database, :db
|
59
|
+
|
60
|
+
def dbm
|
61
|
+
controller.dbm
|
62
|
+
end
|
63
|
+
alias_method :models, :dbm
|
64
|
+
|
65
|
+
def app(*args)
|
66
|
+
controller.app(*args)
|
67
|
+
end
|
68
|
+
|
69
|
+
def host
|
70
|
+
controller.host
|
71
|
+
end
|
72
|
+
|
73
|
+
def action
|
74
|
+
controller.action
|
75
|
+
end
|
76
|
+
|
77
|
+
def extension
|
78
|
+
controller.extension
|
79
|
+
end
|
80
|
+
|
81
|
+
def action_subdir
|
82
|
+
controller.action_subdir
|
83
|
+
end
|
84
|
+
|
85
|
+
def upload_dir
|
86
|
+
controller.upload_dir
|
87
|
+
end
|
88
|
+
|
89
|
+
def arg(index)
|
90
|
+
controller.args[index]
|
91
|
+
end
|
92
|
+
|
93
|
+
def authenticate
|
94
|
+
controller.authenticate
|
95
|
+
end
|
96
|
+
|
97
|
+
def new_email
|
98
|
+
controller.new_email
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|