picnic 0.7.1 → 0.8.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/History.txt +10 -0
- data/Manifest.txt +30 -13
- data/Rakefile +2 -0
- data/lib/picnic.rb +5 -120
- data/lib/picnic/authentication.rb +40 -4
- data/lib/picnic/cli.rb +86 -43
- data/lib/picnic/conf.rb +45 -43
- data/lib/picnic/logger.rb +41 -0
- data/lib/picnic/server.rb +99 -0
- data/lib/picnic/version.rb +2 -2
- data/picnic.gemspec +44 -0
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/CHANGELOG +17 -10
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/COPYING +0 -0
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/README +2 -2
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/Rakefile +62 -5
- data/vendor/camping-2.0.20090212/bin/camping +99 -0
- data/vendor/camping-2.0.20090212/doc/camping.1.gz +0 -0
- data/vendor/camping-2.0.20090212/examples/README +5 -0
- data/vendor/camping-2.0.20090212/examples/blog.rb +375 -0
- data/vendor/camping-2.0.20090212/examples/campsh.rb +629 -0
- data/vendor/camping-2.0.20090212/examples/tepee.rb +242 -0
- data/vendor/camping-2.0.20090212/extras/Camping.gif +0 -0
- data/vendor/camping-2.0.20090212/extras/flipbook_rdoc.rb +491 -0
- data/vendor/camping-2.0.20090212/extras/permalink.gif +0 -0
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/lib/camping-unabridged.rb +168 -294
- data/vendor/camping-2.0.20090212/lib/camping.rb +54 -0
- data/vendor/{camping-1.5.180/lib/camping/db.rb → camping-2.0.20090212/lib/camping/ar.rb} +4 -4
- data/vendor/{camping-1.5.180/lib/camping → camping-2.0.20090212/lib/camping/ar}/session.rb +23 -14
- data/vendor/camping-2.0.20090212/lib/camping/mab.rb +26 -0
- data/vendor/camping-2.0.20090212/lib/camping/reloader.rb +163 -0
- data/vendor/camping-2.0.20090212/lib/camping/server.rb +158 -0
- data/vendor/camping-2.0.20090212/lib/camping/session.rb +74 -0
- data/vendor/camping-2.0.20090212/setup.rb +1551 -0
- data/vendor/camping-2.0.20090212/test/apps/env_debug.rb +65 -0
- data/vendor/camping-2.0.20090212/test/apps/forms.rb +95 -0
- data/vendor/camping-2.0.20090212/test/apps/misc.rb +86 -0
- data/vendor/camping-2.0.20090212/test/apps/sessions.rb +38 -0
- data/vendor/camping-2.0.20090212/test/test_camping.rb +54 -0
- metadata +43 -16
- data/lib/picnic/postambles.rb +0 -292
- data/lib/picnic/utils.rb +0 -36
- data/vendor/camping-1.5.180/lib/camping.rb +0 -57
- data/vendor/camping-1.5.180/lib/camping/fastcgi.rb +0 -244
- data/vendor/camping-1.5.180/lib/camping/reloader.rb +0 -163
- data/vendor/camping-1.5.180/lib/camping/webrick.rb +0 -65
@@ -0,0 +1,99 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
trap("INT") { exit }
|
4
|
+
require 'optparse'
|
5
|
+
require 'ostruct'
|
6
|
+
require 'stringio'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
$:.unshift File.dirname(__FILE__) + "/../lib"
|
10
|
+
require 'camping'
|
11
|
+
require 'camping/server'
|
12
|
+
|
13
|
+
conf = OpenStruct.new(:host => '0.0.0.0', :port => 3301)
|
14
|
+
|
15
|
+
# Setup paths
|
16
|
+
if home = ENV['HOME'] # POSIX
|
17
|
+
db_path = File.join(home, '.camping.db')
|
18
|
+
rc_path = File.join(home, '.campingrc')
|
19
|
+
elsif home = ENV['APPDATA'] # MSWIN
|
20
|
+
db_path = File.join(home, 'Camping.db')
|
21
|
+
rc_path = File.join(home, 'Campingrc')
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parse options
|
25
|
+
opts = OptionParser.new do |opts|
|
26
|
+
opts.banner = "Usage: camping app1.rb, app2.rb..."
|
27
|
+
opts.define_head "#{File.basename($0)}, the microframework ON-button for ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
|
28
|
+
opts.separator ""
|
29
|
+
opts.separator "Specific options:"
|
30
|
+
|
31
|
+
opts.on("-h", "--host HOSTNAME", "Host for web server to bind to (default is all IPs)") { |conf.host| }
|
32
|
+
opts.on("-p", "--port NUM", "Port for web server (defaults to #{conf.port})") { |conf.port| }
|
33
|
+
opts.on("-d", "--database FILE", "SQLite3 database path (defaults to #{db_path ? db_path : '<none>'})") { |db_path| conf.database = {:adapter => 'sqlite3', :database => db_path} }
|
34
|
+
opts.on("-l", "--log FILE", "Start a database log ('-' for STDOUT)") { |conf.log| }
|
35
|
+
opts.on("-C", "--console", "Run in console mode with IRB") { conf.server = "console" }
|
36
|
+
server_list = ["mongrel", "webrick", "console"]
|
37
|
+
opts.on("-s", "--server NAME", server_list, "Server to force (#{server_list.join(', ')})") { |conf.server| }
|
38
|
+
|
39
|
+
opts.separator ""
|
40
|
+
opts.separator "Common options:"
|
41
|
+
|
42
|
+
# No argument, shows at tail. This will print an options summary.
|
43
|
+
# Try it and see!
|
44
|
+
opts.on_tail("-?", "--help", "Show this message") do
|
45
|
+
puts opts
|
46
|
+
exit
|
47
|
+
end
|
48
|
+
|
49
|
+
# Another typical switch to print the version.
|
50
|
+
opts.on_tail("-v", "--version", "Show version") do
|
51
|
+
class << Gem; attr_accessor :loaded_specs; end
|
52
|
+
puts Gem.loaded_specs['camping'].version
|
53
|
+
exit
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
begin
|
58
|
+
opts.parse! ARGV
|
59
|
+
rescue OptionParser::ParseError => ex
|
60
|
+
STDERR.puts "!! #{ex.message}"
|
61
|
+
puts "** use `#{File.basename($0)} --help` for more details..."
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
|
65
|
+
if ARGV.length < 1
|
66
|
+
puts opts
|
67
|
+
exit 1
|
68
|
+
end
|
69
|
+
|
70
|
+
# Load configuration if any
|
71
|
+
if rc_path and File.exists?( rc_path )
|
72
|
+
YAML.load_file(rc_path).each do |k,v|
|
73
|
+
conf.send("#{k}=", v) unless conf.send(k)
|
74
|
+
end
|
75
|
+
puts "** conf file #{rc_path} loaded"
|
76
|
+
end
|
77
|
+
|
78
|
+
# Default db
|
79
|
+
if conf.database.nil? and db_path
|
80
|
+
conf.database = {:adapter => 'sqlite3', :database => db_path} if db_path
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
# get a copy of the paths to pass to the server
|
85
|
+
paths = ARGV.dup
|
86
|
+
|
87
|
+
# Check that mongrel exists
|
88
|
+
if conf.server.nil? || conf.server == "mongrel"
|
89
|
+
begin
|
90
|
+
require 'mongrel'
|
91
|
+
conf.server = "mongrel"
|
92
|
+
rescue LoadError
|
93
|
+
puts "!! could not load mongrel. Falling back to webrick."
|
94
|
+
conf.server = "webrick"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
server = Camping::Server::Base.new(conf, paths)
|
99
|
+
server.start
|
Binary file
|
@@ -0,0 +1,375 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
4
|
+
require 'camping'
|
5
|
+
require 'camping/ar'
|
6
|
+
require 'camping/session'
|
7
|
+
require 'redcloth'
|
8
|
+
|
9
|
+
Camping.goes :Blog
|
10
|
+
|
11
|
+
module Blog
|
12
|
+
include Camping::Session
|
13
|
+
|
14
|
+
module Models
|
15
|
+
class Post < Base
|
16
|
+
belongs_to :user
|
17
|
+
|
18
|
+
before_save do |record|
|
19
|
+
cloth = RedCloth.new(record.body)
|
20
|
+
cloth.hard_breaks = false
|
21
|
+
record.html_body = cloth.to_html
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Comment < Base; belongs_to :user; end
|
26
|
+
class User < Base; end
|
27
|
+
|
28
|
+
class BasicFields < V 1.1
|
29
|
+
def self.up
|
30
|
+
create_table :blog_posts, :force => true do |t|
|
31
|
+
t.integer :user_id, :null => false
|
32
|
+
t.string :title, :limit => 255
|
33
|
+
t.text :body, :html_body
|
34
|
+
t.timestamps
|
35
|
+
end
|
36
|
+
create_table :blog_users, :force => true do |t|
|
37
|
+
t.string :username, :password
|
38
|
+
end
|
39
|
+
create_table :blog_comments, :force => true do |t|
|
40
|
+
t.integer :post_id, :null => false
|
41
|
+
t.string :username
|
42
|
+
t.text :body, :html_body
|
43
|
+
t.timestamps
|
44
|
+
end
|
45
|
+
User.create :username => 'admin', :password => 'camping'
|
46
|
+
end
|
47
|
+
def self.down
|
48
|
+
drop_table :blog_posts
|
49
|
+
drop_table :blog_users
|
50
|
+
drop_table :blog_comments
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
module Controllers
|
56
|
+
class Index
|
57
|
+
def get
|
58
|
+
@posts = Post.all(:order => 'updated_at DESC')
|
59
|
+
render :index
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class PostNew
|
64
|
+
def get
|
65
|
+
require_login!
|
66
|
+
@post = Post.new
|
67
|
+
render :add
|
68
|
+
end
|
69
|
+
|
70
|
+
def post
|
71
|
+
require_login!
|
72
|
+
post = Post.create(:title => input.post_title, :body => input.post_body,
|
73
|
+
:user_id => @state.user_id)
|
74
|
+
redirect PostN, post
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class PostN
|
79
|
+
def get(post_id)
|
80
|
+
@post = Post.find(post_id)
|
81
|
+
render :view
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class Edit < R '/post/(\d+)/edit'
|
86
|
+
def get(post_id)
|
87
|
+
require_login!
|
88
|
+
@post = Post.find(post_id)
|
89
|
+
render :edit
|
90
|
+
end
|
91
|
+
|
92
|
+
def post(post_id)
|
93
|
+
require_login!
|
94
|
+
@post = Post.find(post_id)
|
95
|
+
@post.update_attributes :title => input.post_title, :body => input.post_body
|
96
|
+
redirect PostN, @post
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class Login
|
101
|
+
def get
|
102
|
+
@to = input.to
|
103
|
+
render :login
|
104
|
+
end
|
105
|
+
|
106
|
+
def post
|
107
|
+
@user = User.find_by_username_and_password(input.username, input.password)
|
108
|
+
@to = input.to
|
109
|
+
|
110
|
+
if @user
|
111
|
+
@state.user_id = @user.id
|
112
|
+
if @to
|
113
|
+
redirect @to
|
114
|
+
else
|
115
|
+
redirect R(Index)
|
116
|
+
end
|
117
|
+
else
|
118
|
+
@info = 'Wrong username or password'
|
119
|
+
end
|
120
|
+
render :login
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class Logout
|
125
|
+
def get
|
126
|
+
@state.user_id = nil
|
127
|
+
redirect Index
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class Style < R '/styles\.css'
|
132
|
+
STYLE = File.read(__FILE__).gsub(/.*__END__/m, '')
|
133
|
+
|
134
|
+
def get
|
135
|
+
@headers['Content-Type'] = 'text/css; charset=utf-8'
|
136
|
+
STYLE
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
module Helpers
|
142
|
+
def logged_in?
|
143
|
+
!!@state.user_id
|
144
|
+
end
|
145
|
+
|
146
|
+
def require_login!
|
147
|
+
unless logged_in?
|
148
|
+
redirect X::Login, :to => @env.REQUEST_URI
|
149
|
+
throw :halt
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
module Views
|
155
|
+
def layout
|
156
|
+
html do
|
157
|
+
head do
|
158
|
+
title 'My Blog'
|
159
|
+
link :rel => 'stylesheet', :type => 'text/css',
|
160
|
+
:href => '/styles.css', :media => 'screen'
|
161
|
+
end
|
162
|
+
body do
|
163
|
+
h1 { a 'My Blog', :href => R(Index) }
|
164
|
+
|
165
|
+
div.wrapper! do
|
166
|
+
text yield
|
167
|
+
end
|
168
|
+
|
169
|
+
hr
|
170
|
+
|
171
|
+
p.footer! do
|
172
|
+
if logged_in?
|
173
|
+
_admin_menu
|
174
|
+
else
|
175
|
+
a 'Login', :href => R(Login, :to => @env.REQUEST_URI)
|
176
|
+
text ' to the adminpanel'
|
177
|
+
end
|
178
|
+
text ' – Powered by '
|
179
|
+
a 'Camping', :href => 'http://code.whytheluckystiff.net/camping'
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def index
|
186
|
+
if @posts.empty?
|
187
|
+
h2 'No posts'
|
188
|
+
p do
|
189
|
+
text 'Could not find any posts. Feel free to '
|
190
|
+
a 'add one', :href => R(PostNew)
|
191
|
+
text ' yourself'
|
192
|
+
end
|
193
|
+
else
|
194
|
+
@posts.each do |post|
|
195
|
+
_post(post)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def login
|
201
|
+
h2 'Login'
|
202
|
+
p.info @info if @info
|
203
|
+
|
204
|
+
form :action => R(Login), :method => 'post' do
|
205
|
+
input :name => 'to', :type => 'hidden', :value => @to if @to
|
206
|
+
|
207
|
+
label 'Username', :for => 'username'
|
208
|
+
input :name => 'username', :id => 'username', :type => 'text'
|
209
|
+
|
210
|
+
label 'Password', :for => 'password'
|
211
|
+
input :name => 'password', :id => 'password', :type => 'password'
|
212
|
+
|
213
|
+
input :type => 'submit', :class => 'submit', :value => 'Login'
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def add
|
218
|
+
_form(@post, :action => R(PostNew))
|
219
|
+
end
|
220
|
+
|
221
|
+
def edit
|
222
|
+
_form(@post, :action => R(Edit, @post))
|
223
|
+
end
|
224
|
+
|
225
|
+
def view
|
226
|
+
_post(@post)
|
227
|
+
end
|
228
|
+
|
229
|
+
# partials
|
230
|
+
def _admin_menu
|
231
|
+
text [['Log out', R(Logout)], ['New', R(PostNew)]].map { |name, to|
|
232
|
+
capture { a name, :href => to}
|
233
|
+
}.join(' – ')
|
234
|
+
end
|
235
|
+
|
236
|
+
def _post(post)
|
237
|
+
h2 post.title
|
238
|
+
p.info do
|
239
|
+
text "Written by <strong>#{post.user.username}</strong> "
|
240
|
+
text post.updated_at.strftime('%B %M, %Y @ %H:%M ')
|
241
|
+
_post_menu(post)
|
242
|
+
end
|
243
|
+
text post.html_body
|
244
|
+
end
|
245
|
+
|
246
|
+
def _post_menu(post)
|
247
|
+
text '('
|
248
|
+
a 'view', :href => R(PostN, post)
|
249
|
+
if logged_in?
|
250
|
+
text ', '
|
251
|
+
a 'edit', :href => R(Edit, post)
|
252
|
+
end
|
253
|
+
text ')'
|
254
|
+
end
|
255
|
+
|
256
|
+
def _form(post, opts)
|
257
|
+
form({:method => 'post'}.merge(opts)) do
|
258
|
+
label 'Title', :for => 'post_title'
|
259
|
+
input :name => 'post_title', :id => 'post_title', :type => 'text',
|
260
|
+
:value => post.title
|
261
|
+
|
262
|
+
label 'Body', :for => 'post_body'
|
263
|
+
textarea post.body, :name => 'post_body', :id => 'post_body'
|
264
|
+
|
265
|
+
input :type => 'hidden', :name => 'post_id', :value => post.id
|
266
|
+
input :type => 'submit', :class => 'submit', :value => 'Submit'
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def Blog.create
|
273
|
+
Blog::Models.create_schema :assume => (Blog::Models::Post.table_exists? ? 1.0 : 0.0)
|
274
|
+
end
|
275
|
+
|
276
|
+
__END__
|
277
|
+
* {
|
278
|
+
margin: 0;
|
279
|
+
padding: 0;
|
280
|
+
}
|
281
|
+
|
282
|
+
body {
|
283
|
+
font: normal 14px Arial, 'Bitstream Vera Sans', Helvetica, sans-serif;
|
284
|
+
line-height: 1.5;
|
285
|
+
}
|
286
|
+
|
287
|
+
h1, h2, h3, h4 {
|
288
|
+
font-family: Georgia, serif;
|
289
|
+
font-weight: normal;
|
290
|
+
}
|
291
|
+
|
292
|
+
h1 {
|
293
|
+
background-color: #EEE;
|
294
|
+
border-bottom: 5px solid #6F812D;
|
295
|
+
outline: 5px solid #9CB441;
|
296
|
+
font-weight: normal;
|
297
|
+
font-size: 3em;
|
298
|
+
padding: 0.5em 0;
|
299
|
+
text-align: center;
|
300
|
+
}
|
301
|
+
|
302
|
+
h1 a { color: #143D55; text-decoration: none }
|
303
|
+
h1 a:hover { color: #143D55; text-decoration: underline }
|
304
|
+
|
305
|
+
h2 {
|
306
|
+
font-size: 2em;
|
307
|
+
color: #287AA9;
|
308
|
+
}
|
309
|
+
|
310
|
+
#wrapper {
|
311
|
+
margin: 3em auto;
|
312
|
+
width: 700px;
|
313
|
+
}
|
314
|
+
|
315
|
+
p {
|
316
|
+
margin-bottom: 1em;
|
317
|
+
}
|
318
|
+
|
319
|
+
p.info, p#footer {
|
320
|
+
color: #999;
|
321
|
+
margin-left: 1em;
|
322
|
+
}
|
323
|
+
|
324
|
+
p.info a, p#footer a {
|
325
|
+
color: #999;
|
326
|
+
}
|
327
|
+
|
328
|
+
p.info a:hover, p#footer a:hover {
|
329
|
+
text-decoration: none;
|
330
|
+
}
|
331
|
+
|
332
|
+
a {
|
333
|
+
color: #6F812D;
|
334
|
+
}
|
335
|
+
|
336
|
+
a:hover {
|
337
|
+
color: #9CB441;
|
338
|
+
}
|
339
|
+
|
340
|
+
hr {
|
341
|
+
border-width: 5px 0;
|
342
|
+
border-style: solid;
|
343
|
+
border-color: #9CB441;
|
344
|
+
border-bottom-color: #6F812D;
|
345
|
+
height: 0;
|
346
|
+
}
|
347
|
+
|
348
|
+
p#footer {
|
349
|
+
font-size: 0.9em;
|
350
|
+
margin: 0;
|
351
|
+
padding: 1em;
|
352
|
+
text-align: center;
|
353
|
+
}
|
354
|
+
|
355
|
+
label {
|
356
|
+
display: inline-block;
|
357
|
+
width: 100%;
|
358
|
+
}
|
359
|
+
|
360
|
+
input, textarea {
|
361
|
+
margin-bottom: 1em;
|
362
|
+
width: 200px;
|
363
|
+
}
|
364
|
+
|
365
|
+
input.submit {
|
366
|
+
float: left;
|
367
|
+
width: auto;
|
368
|
+
}
|
369
|
+
|
370
|
+
textarea {
|
371
|
+
font: normal 14px Arial, 'Bitstream Vera Sans', Helvetica, sans-serif;
|
372
|
+
height: 300px;
|
373
|
+
width: 400px;
|
374
|
+
}
|
375
|
+
|