camping 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #$:.unshift File.dirname(__FILE__) + "/../../lib"
4
+ require 'rubygems'
5
+ require 'camping'
6
+
7
+ module Camping::Models
8
+ class Post < Base; belongs_to :user; end
9
+ class Comment < Base; belongs_to :user; end
10
+ class User < Base; end
11
+ end
12
+
13
+ module Camping::Controllers
14
+ class Index < R '/'
15
+ def get
16
+ @posts = Post.find :all
17
+ render :index
18
+ end
19
+ end
20
+
21
+ class Add
22
+ def get
23
+ if cookies.user_id
24
+ @session = User.find cookies.user_id
25
+ end
26
+ render :add
27
+ end
28
+ def post
29
+ post = Post.create :title => input.post_title, :body => input.post_body
30
+ redirect View, post
31
+ end
32
+ end
33
+
34
+ class Info
35
+ def get
36
+ pre cookies.inspect
37
+ end
38
+ end
39
+
40
+ class View < R '/view/(\d+)'
41
+ def get post_id
42
+ @post = Post.find post_id
43
+ @comments = Comment.find :all, :conditions => ['post_id = ?', post_id]
44
+ render :view
45
+ end
46
+ end
47
+
48
+ class Edit < R '/edit/(\d+)', '/edit'
49
+ def get post_id
50
+ if cookies.user_id
51
+ @session = User.find cookies.user_id
52
+ end
53
+ @post = Post.find post_id
54
+ render :edit
55
+ end
56
+
57
+ def post
58
+ @post = Post.find input.post_id
59
+ @post.update_attributes :title => input.post_title, :body => input.post_body
60
+ redirect View, @post
61
+ end
62
+ end
63
+
64
+ class Comment
65
+ def post
66
+ Comment.create(:username => input.post_username,
67
+ :body => input.post_body, :post_id => input.post_id)
68
+ redirect View, input.post_id
69
+ end
70
+ end
71
+
72
+ class Login
73
+ def post
74
+ @user = User.find :first, :conditions => ['username = ? AND password = ?', input.username, input.password]
75
+
76
+ if @user
77
+ @login = 'login success !'
78
+ cookies.user_id = @user.id
79
+ else
80
+ @login = 'wrong user name or password'
81
+ end
82
+ render :login
83
+ end
84
+ end
85
+
86
+ class Logout
87
+ def get
88
+ cookies.user_id = nil
89
+ render :logout
90
+ end
91
+ end
92
+
93
+ class Style < R '/styles.css', '/view/styles.css'
94
+ def get
95
+ @headers["Content-Type"] = "text/css; charset=utf-8"
96
+ @body = File.read('styles.css')
97
+ end
98
+ end
99
+ end
100
+
101
+ module Camping::Views
102
+
103
+ def layout
104
+ html do
105
+ head do
106
+ title 'blog'
107
+ link :rel => 'stylesheet', :type => 'text/css',
108
+ :href => 'styles.css', :media => 'screen'
109
+ end
110
+ body do
111
+ h1.header { a 'blog', :href => '/' }
112
+ div.content do
113
+ self << yield
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ def index
120
+ if @posts.empty?
121
+ p 'No posts found.'
122
+ p { a 'Add', :href => '/add' }
123
+ else
124
+ for post in @posts
125
+ _post(post)
126
+ end
127
+ end
128
+ end
129
+
130
+ def login
131
+ p { b @login }
132
+ p { a 'Continue', :href => '/add' }
133
+ end
134
+
135
+ def logout
136
+ p "You have been logged out."
137
+ p { a 'Continue', :href => '/' }
138
+ end
139
+
140
+ def add
141
+ if @session
142
+ _form(post, :action => '/add')
143
+ else
144
+ _login
145
+ end
146
+ end
147
+
148
+ def edit
149
+ if @session
150
+ _form(post, :action => '/edit')
151
+ else
152
+ _login
153
+ end
154
+ end
155
+
156
+ def view
157
+ _post(post)
158
+
159
+ p "Comment for this post:"
160
+ for c in @comments
161
+ h1 c.username
162
+ p c.body
163
+ end
164
+
165
+ form :action => '/comment', :method => 'post' do
166
+ label 'Name', :for => 'post_username'; br
167
+ input :name => 'post_username', :type => 'text'; br
168
+ label 'Comment', :for => 'post_body'; br
169
+ textarea :name => 'post_body' do; end; br
170
+ input :type => 'hidden', :name => 'post_id', :value => post.id
171
+ input :type => 'submit'
172
+ end
173
+ end
174
+
175
+ # partials
176
+ def _login
177
+ form :action => '/login', :method => 'post' do
178
+ label 'Username', :for => 'username'; br
179
+ input :name => 'username', :type => 'text'; br
180
+
181
+ label 'Password', :for => 'password'; br
182
+ input :name => 'password', :type => 'text'; br
183
+
184
+ input :type => 'submit', :name => 'login', :value => 'Login'
185
+ end
186
+ end
187
+
188
+ def _post(post)
189
+ h1 post.title
190
+ p post.body
191
+ p do
192
+ a "Edit", :href => "/edit/#{post.id}"
193
+ a "View", :href => "/view/#{post.id}"
194
+ end
195
+ end
196
+
197
+ def _form(post, opts)
198
+ p do
199
+ text "You are logged in as #{@session.username} | "
200
+ a 'Logout', :href => '/logout'
201
+ end
202
+ form({:method => 'post'}.merge(opts)) do
203
+ label 'Title', :for => 'post_title'; br
204
+ input :name => 'post_title', :type => 'text',
205
+ :value => post.title; br
206
+
207
+ label 'Body', :for => 'post_body'; br
208
+ textarea post.body, :name => 'post_body'; br
209
+
210
+ input :type => 'hidden', :name => 'post_id', :value => post.id
211
+ input :type => 'submit'
212
+ end
213
+ end
214
+ end
215
+
216
+ if __FILE__ == $0
217
+ Camping::Models::Base.establish_connection :adapter => 'sqlite3', :database => 'blog3.db'
218
+ Camping::Models::Base.logger = Logger.new('camping.log')
219
+ Camping.run
220
+ end
@@ -0,0 +1,21 @@
1
+ CREATE TABLE posts (
2
+ id integer primary key,
3
+ user_id integer,
4
+ title text,
5
+ body text,
6
+ at date
7
+ );
8
+
9
+ CREATE TABLE users (
10
+ id integer primary key,
11
+ username text,
12
+ password text
13
+ );
14
+
15
+ CREATE TABLE comments (
16
+ id integer primary key,
17
+ post_id integer,
18
+ username text,
19
+ body text,
20
+ created_at date
21
+ );
Binary file
@@ -0,0 +1,16 @@
1
+ # Logfile created on Tue Jan 17 22:57:14 MST 2006 by logger.rb/1.5.2.4
2
+ Camping::Models::Post Load (0.000000) SQLite3::SQLException: no such table: posts: SELECT * FROM posts 
3
+ Camping::Models::Post Load (0.000764) SELECT * FROM posts 
4
+ Camping::Models::Post Load (0.000776) SELECT * FROM posts 
5
+ Camping::Models::Post Load (0.000781) SELECT * FROM posts 
6
+ Camping::Models::Post Load (0.000803) SELECT * FROM posts WHERE (posts.id = '1') LIMIT 1
7
+ Camping::Models::Post Load (0.000873) SELECT * FROM posts 
8
+ Camping::Models::Post Load (0.000825) SELECT * FROM posts 
9
+ Camping::Models::Post Load (0.000806) SELECT * FROM posts 
10
+ Camping::Models::Post Load (0.000824) SELECT * FROM posts 
11
+ Camping::Models::Post Load (0.000832) SELECT * FROM posts 
12
+ Camping::Models::Post Load (0.000816) SELECT * FROM posts 
13
+ Camping::Models::Post Load (0.000824) SELECT * FROM posts 
14
+ Camping::Models::Post Load (0.000813) SELECT * FROM posts 
15
+ Camping::Models::Post Load (0.000828) SELECT * FROM posts 
16
+ Camping::Models::User Load (0.000831) SELECT * FROM users WHERE (username = '_why' AND password = 'hacky') LIMIT 1
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/ruby
2
+ require 'webrick/httpserver'
3
+ s = WEBrick::HTTPServer.new(:BindAddress => 'localhost', :Port => 3044)
4
+ s.mount("/", WEBrick::HTTPServlet::CGIHandler, "blog.rb")
5
+ trap( :INT ) { s.shutdown }
6
+ s.start
@@ -0,0 +1,10 @@
1
+ body {
2
+ font-family: Utopia, Georga, serif;
3
+ }
4
+ h1.header {
5
+ background-color: #fef;
6
+ margin: 0; padding: 10px;
7
+ }
8
+ div.content {
9
+ padding: 10px;
10
+ }
@@ -0,0 +1,44 @@
1
+ %w[rubygems active_record markaby metaid ostruct].each {|lib| require lib}
2
+ module Camping;module Models;Base = ActiveRecord::Base;end;module Views;end
3
+ Markaby::Builder.class_eval{include Views};module Controllers;module RM
4
+ attr_accessor :input,:cookies,:headers,:body,:status;def method_missing(m,
5
+ *args, &blk);str=eval("markaby.#{m}(*args, &blk)");str=markaview(:layout){
6
+ str}rescue nil;r(200,str.to_s,'Content-Type'=>'text/html');end;def render(m)
7
+ str = markaview(m);str = markaview(:layout){ str }rescue nil;r(200, str,
8
+ "Content-Type" => 'text/html');end;def redirect(*args);c, *args = args;if \
9
+ c.respond_to? :urls;c = c.urls.first;c.gsub!(/\(.+?\)/) do;((a = args.
10
+ shift).respond_to?(:primary_key) ? a.method(a.primary_key) : a).to_s;end
11
+ end;r(302,'','Location' => c);end;def r(s, b, h = {});@status = s;@headers.
12
+ merge!(h);@body = b;end;def service(e, m, a);@status, @headers = 200,
13
+ {'Content-Type' => 'text/html'};@cookies=Camping.cookie_parse(e['COOKIE']||
14
+ e['HTTP_COOKIE']);cook = @cookies.marshal_dump.dup;if (e['REQUEST_METHOD']==
15
+ 'POST')and %r|\Amultipart/form-data.*boundary=\"?.+?\"?|n=~e['CONTENT_TYPE']
16
+ return r(500, "Urgh, multipart/form-data not yet supported.");else;@input =
17
+ Camping.qs_parse(e['REQUEST_METHOD']!="POST" ? e['QUERY_STRING'] : $stdin.
18
+ read(e['CONTENT_LENGTH'].to_i));end;@body = method( m.downcase ).call(*a)
19
+ @headers['Set-Cookie'] = @cookies.marshal_dump.map { |k,v| "#{k}=#{Camping.
20
+ escape(v)}; path=/"if v != cook[k]}.compact;self;end;def to_s;"Status: #{
21
+ @status}\n#{@headers.map{|k,v|v.to_a.map{|v2|"#{k}: #{v2}"}}.flatten.join(
22
+ "\n")}\n\n#{@body}";end;private;def markaby;Markaby::Builder.new(
23
+ instance_variables.map{|iv|[iv[1..-1].intern, instance_variable_get(iv)] },
24
+ {});end;def markaview(m,*args,&blk);markaby.instance_eval{Views.
25
+ instance_method(m).bind(self).call(*args, &blk); self }.to_s;end;end;class R
26
+ include RM end;class NotFound < R;def get;r(404,h1('Camping Problem!')+h2(
27
+ 'Not Found'))end end;class<<self;def R(*urls);Class.new(R){meta_def(
28
+ :inherited){|c|c.meta_def(:urls){urls}}}end;def D(path);constants.each{|c|
29
+ k=const_get(c);return k,$~[1..-1]if (k.urls rescue "/#{c.downcase}").find{
30
+ |x|path=~/^#{x}\/?$/ };};[NotFound, []]end end end;class Response; include
31
+ Controllers::RM;def initialize(s=200,&blk);@headers,@body,@status={},"",s
32
+ instance_eval &blk end end;class << self;def escape(s); s.to_s.gsub(/([^ \
33
+ a-zA-Z0-9_.-]+)/n){'%'+$1.unpack('H2'*$1.size).join('%').upcase}.tr(' ','+')
34
+ end;def unescape(s);s.tr('+',' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){[$1.delete(
35
+ '%')].pack('H*')}end;def qs_parse(qs,d='&;');OpenStruct.new((qs||'').split(
36
+ /[#{d}] */n).inject({}){|hsh, p|k,v=p.split('=',2).map{|v|unescape(v)};hsh[
37
+ k]=v unless v.empty?;hsh}) end;def cookie_parse(s);c=qs_parse(s,';,') end
38
+ def run;begin;k,a,m=Controllers.D(ENV['PATH_INFO'])+[ENV['REQUEST_METHOD']||
39
+ "GET"];k.class_eval{include Controllers::RM};o=k.new;o.class.class_eval do
40
+ Models.constants.each{|c|g=Models.const_get(c);remove_const c if
41
+ const_defined? c;const_set c,g};end;puts o.service(ENV, m, a);rescue=>e
42
+ puts Response.new(200){@headers['Content-Type']='text/html';@body=Markaby::
43
+ Builder.new({},{}){h1'Camping Problem!';h2"#{k}.#{m}";h3"#{e.class} \
44
+ #{e.message}:";ul{e.backtrace.each{|bt|li bt}}}.to_s};end end end end
data/lib/camping.rb ADDED
@@ -0,0 +1,105 @@
1
+ %w[rubygems active_record markaby metaid ostruct].each { |lib| require lib }
2
+
3
+ module Camping
4
+ module Models; end ; module Views; end ; Models::Base = ActiveRecord::Base
5
+ Markaby::Builder.class_eval { include Views }
6
+
7
+ module Controllers
8
+ module RM
9
+ attr_accessor :input, :cookies, :headers, :body, :status
10
+ def method_missing(m, *args, &blk)
11
+ str = eval("markaby.#{m}(*args, &blk)")
12
+ str = markaview(:layout) { str } rescue nil
13
+ r(200, str.to_s, 'Content-Type' => 'text/html')
14
+ end
15
+ def render(m)
16
+ str = markaview(m)
17
+ str = markaview(:layout) { str } rescue nil
18
+ r(200, str, "Content-Type" => 'text/html')
19
+ end
20
+ def redirect(*args)
21
+ c, *args = args
22
+ if c.respond_to? :urls
23
+ c = c.urls.first
24
+ c.gsub!(/\(.+?\)/) do
25
+ ((a = args.shift).respond_to?(:primary_key) ? a.method(a.primary_key) : a).to_s
26
+ end
27
+ end
28
+ r(302, '', 'Location' => c)
29
+ end
30
+ def r(s, b, h = {}); @status = s; @headers.merge!(h); @body = b; end
31
+ def service(e, m, a)
32
+ @status, @headers = 200, {'Content-Type' => 'text/html'}
33
+ @cookies = Camping.cookie_parse(e['HTTP_COOKIE'] || e['COOKIE'])
34
+ cook = @cookies.marshal_dump.dup
35
+ if ("POST" == e['REQUEST_METHOD']) and
36
+ %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n.match(e['CONTENT_TYPE'])
37
+ return r(500, "Urgh, multipart/form-data not yet supported.")
38
+ else
39
+ @input = Camping.qs_parse(e['REQUEST_METHOD'] == "POST" ?
40
+ $stdin.read(e['CONTENT_LENGTH'].to_i) : e['QUERY_STRING'])
41
+ end
42
+
43
+ @body = method( m.downcase ).call(*a)
44
+ @headers['Set-Cookie'] = @cookies.marshal_dump.map { |k,v| "#{k}=#{Camping.escape(v)}; path=/" if v != cook[k] }.compact
45
+ self
46
+ end
47
+ def to_s
48
+ "Status: #{@status}\n#{@headers.map{|k,v|v.to_a.map{|v2|"#{k}: #{v2}"}}.flatten.join("\n")}\n\n#{@body}"
49
+ end
50
+ private
51
+ def markaby
52
+ Markaby::Builder.new( instance_variables.map { |iv|
53
+ [iv[1..-1].intern, instance_variable_get(iv)] }, {} )
54
+ end
55
+ def markaview(m, *args, &blk)
56
+ markaby.instance_eval { Views.instance_method(m).bind(self).call(*args, &blk); self }.to_s
57
+ end
58
+ end
59
+ class R; include RM end
60
+ class NotFound < R; def get; r(404, h1('Camping Problem!') + h2('Not Found')); end end
61
+
62
+ class << self
63
+ def R(*urls); Class.new(R) { meta_def(:inherited) { |c| c.meta_def(:urls) { urls } } }; end
64
+ def D(path)
65
+ constants.each do |c|
66
+ k = const_get(c)
67
+ return k, $~[1..-1] if (k.urls rescue "/#{c.downcase}").find { |x| path =~ /^#{x}\/?$/ }
68
+ end
69
+ [NotFound, []]
70
+ end
71
+ end
72
+ end
73
+
74
+ class Response; include Controllers::RM
75
+ def initialize(s = 200, &blk)
76
+ @headers, @body, @status = {}, "", s
77
+ instance_eval &blk
78
+ end
79
+ end
80
+
81
+ class << self
82
+ def escape(s); s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n){'%'+$1.unpack('H2'*$1.size).join('%').upcase}.tr(' ', '+') end
83
+ def unescape(s); s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){[$1.delete('%')].pack('H*')} end
84
+ def qs_parse(qs, d = '&;'); OpenStruct.new((qs||'').split(/[#{d}] */n).
85
+ inject({}){|hsh, p|k, v = p.split('=',2).map {|v| unescape(v)}; hsh[k] = v unless v.empty?; hsh}) end
86
+ def cookie_parse(s); c = qs_parse(s, ';,'); end
87
+ def run
88
+ begin
89
+ k, a, m = Controllers.D(ENV['PATH_INFO']) + [ENV['REQUEST_METHOD'] || "GET"]
90
+ k.class_eval { include Controllers::RM }
91
+ o = k.new
92
+ o.class.class_eval do
93
+ Models.constants.each do |c|
94
+ g = Models.const_get(c)
95
+ remove_const c if const_defined? c
96
+ const_set c, g
97
+ end
98
+ end
99
+ puts o.service(ENV, m, a)
100
+ rescue => e
101
+ puts Response.new(200) { @headers['Content-Type'] = 'text/html'; @body = Markaby::Builder.new({}, {}) { h1 'Camping Problem!'; h2 "#{k}.#{m}"; h3 "#{e.class} #{e.message}:"; ul { e.backtrace.each { |bt| li bt } } }.to_s }
102
+ end
103
+ end
104
+ end
105
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: camping
5
+ version: !ruby/object:Gem::Version
6
+ version: "1.0"
7
+ date: 2006-01-18 00:00:00 -07:00
8
+ summary: miniature rails for stay-at-home moms
9
+ require_paths:
10
+ - lib
11
+ email: why@ruby-lang.org
12
+ homepage: http://whytheluckystiff.net/camping/
13
+ rubyforge_project: hobix
14
+ description:
15
+ autorequire: camping
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ -
22
+ - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ platform: ruby
27
+ signing_key:
28
+ cert_chain:
29
+ authors:
30
+ - why the lucky stiff
31
+ files:
32
+ - examples/blog
33
+ - examples/blog/blog.sqlite3
34
+ - examples/blog/blog.rb
35
+ - examples/blog/camping.log
36
+ - examples/blog/start
37
+ - examples/blog/blog3.db
38
+ - examples/blog/styles.css
39
+ - lib/camping-mural.rb
40
+ - lib/camping.rb
41
+ test_files: []
42
+ rdoc_options: []
43
+ extra_rdoc_files: []
44
+ executables: []
45
+ extensions: []
46
+ requirements: []
47
+ dependencies:
48
+ - !ruby/object:Gem::Dependency
49
+ name: activerecord
50
+ version_requirement:
51
+ version_requirements: !ruby/object:Gem::Version::Requirement
52
+ requirements:
53
+ -
54
+ - ">"
55
+ - !ruby/object:Gem::Version
56
+ version: 0.0.0
57
+ version:
58
+ - !ruby/object:Gem::Dependency
59
+ name: markaby
60
+ version_requirement:
61
+ version_requirements: !ruby/object:Gem::Version::Requirement
62
+ requirements:
63
+ -
64
+ - ">"
65
+ - !ruby/object:Gem::Version
66
+ version: 0.0.0
67
+ version:
68
+ - !ruby/object:Gem::Dependency
69
+ name: metaid
70
+ version_requirement:
71
+ version_requirements: !ruby/object:Gem::Version::Requirement
72
+ requirements:
73
+ -
74
+ - ">"
75
+ - !ruby/object:Gem::Version
76
+ version: 0.0.0
77
+ version: