slippers 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README +56 -0
- data/Rakefile +27 -0
- data/VERSION.yml +4 -0
- data/examples/blog/README +3 -0
- data/examples/blog/blog.db +0 -0
- data/examples/blog/controller/main.rb +30 -0
- data/examples/blog/model/entry.rb +31 -0
- data/examples/blog/public/styles/blog.css +132 -0
- data/examples/blog/spec/blog.rb +87 -0
- data/examples/blog/start.rb +7 -0
- data/examples/blog/view/edit.st +19 -0
- data/examples/blog/view/edit.xhtml +17 -0
- data/examples/blog/view/entry.st +12 -0
- data/examples/blog/view/index.st +4 -0
- data/examples/blog/view/index.xhtml +17 -0
- data/examples/blog/view/layout.st +11 -0
- data/examples/blog/view/layout.xhtml +11 -0
- data/examples/blog/view/new.st +16 -0
- data/examples/blog/view/new.xhtml +16 -0
- data/examples/forms/Rakefile +22 -0
- data/examples/forms/controller/init.rb +12 -0
- data/examples/forms/controller/main.rb +20 -0
- data/examples/forms/controller/registration.rb +24 -0
- data/examples/forms/forms.db +0 -0
- data/examples/forms/model/core_extensions/string_extensions.rb +5 -0
- data/examples/forms/model/field.rb +33 -0
- data/examples/forms/model/form.rb +33 -0
- data/examples/forms/model/init.rb +18 -0
- data/examples/forms/model/orm/registration.rb +12 -0
- data/examples/forms/model/registration_form_builder.rb +7 -0
- data/examples/forms/model/registration_repository.rb +39 -0
- data/examples/forms/model/registration_rules/incorrect_email_format.rb +11 -0
- data/examples/forms/model/registration_rules/number_field.rb +10 -0
- data/examples/forms/model/registration_rules/required_field.rb +9 -0
- data/examples/forms/model/registration_validator.rb +17 -0
- data/examples/forms/public/css/ramaze_error.css +90 -0
- data/examples/forms/public/dispatch.fcgi +11 -0
- data/examples/forms/public/favicon.ico +0 -0
- data/examples/forms/public/js/jquery.js +3549 -0
- data/examples/forms/public/ramaze.png +0 -0
- data/examples/forms/public/web-application.js +0 -0
- data/examples/forms/spec/form_spec.rb +16 -0
- data/examples/forms/spec/main.rb +25 -0
- data/examples/forms/spec/registration_controller_spec.rb +0 -0
- data/examples/forms/spec/registration_repository_spec.rb +38 -0
- data/examples/forms/spec/registration_validator_spec.rb +53 -0
- data/examples/forms/spec/spec_helper.rb +3 -0
- data/examples/forms/start.rb +12 -0
- data/examples/forms/start.ru +16 -0
- data/examples/forms/view/error.xhtml +64 -0
- data/examples/forms/view/index.xhtml +34 -0
- data/examples/forms/view/page.xhtml +27 -0
- data/examples/forms/view/registration/index.st +26 -0
- data/examples/main_controller.rb +40 -0
- data/examples/start.rb +7 -0
- data/examples/todolist/README +1 -0
- data/examples/todolist/controller/main.rb +71 -0
- data/examples/todolist/layout/page.rb +31 -0
- data/examples/todolist/model/tasks.rb +14 -0
- data/examples/todolist/public/favicon.ico +0 -0
- data/examples/todolist/public/js/jquery.js +1923 -0
- data/examples/todolist/public/ramaze.png +0 -0
- data/examples/todolist/start.rb +11 -0
- data/examples/todolist/todolist.db +11 -0
- data/examples/todolist/view/index.st +39 -0
- data/examples/todolist/view/index.xhtml +17 -0
- data/examples/todolist/view/new.st +41 -0
- data/examples/todolist/view/new.xhtml +7 -0
- data/examples/todolist/view/tasks.st +6 -0
- data/examples/todolist.db +5 -0
- data/examples/view/index.st +11 -0
- data/examples/view/person/age.st +1 -0
- data/examples/view/person/age_renderer.rb +6 -0
- data/examples/view/person/index.st +2 -0
- data/lib/engine/binding_wrapper.rb +10 -0
- data/lib/engine/engine.rb +28 -0
- data/lib/engine/file_template.rb +12 -0
- data/lib/engine/slippers.treetop +169 -0
- data/lib/engine/slippers_nodes.rb +119 -0
- data/lib/engine/template.rb +17 -0
- data/lib/engine/template_group.rb +40 -0
- data/lib/engine/template_group_directory.rb +57 -0
- data/lib/ramazeTemplates/0001-Adding-slippers-as-a-new-template.patch +138 -0
- data/lib/ramazeTemplates/0002-Fixing-problem-with-using-other-renderers.patch +27 -0
- data/lib/ramazeTemplates/slippers.rb +22 -0
- data/lib/slippers.rb +14 -0
- data/spec/binding_wrapper.rb +19 -0
- data/spec/engine.rb +89 -0
- data/spec/file_template.rb +9 -0
- data/spec/parse_attributes.rb +98 -0
- data/spec/parse_renderers.rb +35 -0
- data/spec/parse_templates.rb +73 -0
- data/spec/person_template.st +1 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/template_group.rb +52 -0
- data/spec/template_group_directory.rb +43 -0
- data/spec/views/index.st +1 -0
- data/spec/views/money.rb +2 -0
- data/spec/views/person/age.st +1 -0
- data/spec/views/person/date_renderer.rb +5 -0
- data/spec/views/person/name.st +1 -0
- metadata +218 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 starapor
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
There are many template engines that you can choose for the generation of views in your mvc application. The problem with most of the them, however, is that they are too permissive. These turing-complete engines allow for many complex constructs within the template, which begin at simple if statements and for loops, and expand to complex object traversal. While these permissive languages are intended to offer great flexibility, in reality they promote bad practices. Allowing logic to permeate your view is bad for many reasons: firstly, the code in views is rarely tested; secondly, the separation between the models and the view blurs and business logic creeps into the view.
|
2
|
+
|
3
|
+
All we want our template engine to do is read a string which has holes in it, and replace those holes with the desired string, much like mail merge. String Template is a template engine originally for Java but now ported to C# and python, which enforces strict separation of model and view by only supporting these strings with holes. Unfortunately, it has not been ported to ruby...until now.
|
4
|
+
|
5
|
+
Introducing...Slippers, a strict template engine for ruby. Slippers supports the syntax from string template.
|
6
|
+
|
7
|
+
Examples
|
8
|
+
1. Rendering template of a string without any holes
|
9
|
+
template = "This is a string without any holes in it"
|
10
|
+
engine = Slippers::Engine.new(template)
|
11
|
+
engine.render #=> "This is a string without any holes in it"
|
12
|
+
|
13
|
+
2. Filling in a hole within a template
|
14
|
+
template = "This is a string with a message of $message$"
|
15
|
+
engine = Slippers::Engine.new(template)
|
16
|
+
engine.render(:message => "hello world") #=> "This is a string with a message of hello world"
|
17
|
+
|
18
|
+
3. Rendering a subtemplate within a template
|
19
|
+
subtemplate = Slippers::Template.new("this is a subtemplate")
|
20
|
+
template_group = Slippers::TemplateGroup.new(:templates => {:message => subtemplate})
|
21
|
+
template = "This is a template and then $message()$"
|
22
|
+
engine = Slippers::Engine.new(template, :template_group => template_group)
|
23
|
+
engine.render #=> "This is a template and then this is a subtemplate"
|
24
|
+
|
25
|
+
4. Applying an object to a subtemplate
|
26
|
+
subtemplate = Slippers::Template.new("this is a subtemplate with a message of $saying$")
|
27
|
+
template_group = Slippers::TemplateGroup.new(:templates => {:message_subtemplate => subtemplate})
|
28
|
+
template = "This is a template and then $message:message_subtemplate()$!"
|
29
|
+
engine = Slippers::Engine.new(template, :template_group => template_group)
|
30
|
+
engine.render(:message => {:saying => 'hello world'}) #=> "This is a template and then this is a subtemplate with a message of hello world!"
|
31
|
+
|
32
|
+
5. Applying an object to an anonymous subtemplate
|
33
|
+
template = "This is a template and then $message:{this is a subtemplate with a message of $saying$}$!"
|
34
|
+
engine = Slippers::Engine.new(template)
|
35
|
+
engine.render(:message => {:saying => 'hello world'}) #=> "This is a template and then this is a subtemplate with a message of hello world!"
|
36
|
+
|
37
|
+
6. Render a subtemplate using a different rendering technology
|
38
|
+
age_renderer = AgeRenderer.new
|
39
|
+
subtemplate = Slippers::Engine.new('$first$ $last$')
|
40
|
+
person = OpenStruct.new({:name => {:first => 'Fred', :last => 'Flinstone'}, :dob => Date.new(DateTime.now.year - 34, 2, 4)})
|
41
|
+
template_group = Slippers::TemplateGroup.new(:templates => {:name => subtemplate, :age => age_renderer})
|
42
|
+
engine = Slippers::Engine.new("Introducing $name:name()$ who is $dob:age()$.", :template_group => template_group)
|
43
|
+
engine.render(person) #=> "Introducing Fred Flinstone who is 34 years old."
|
44
|
+
|
45
|
+
7. Select a renderer based on the type of the object to render
|
46
|
+
person = OpenStruct.new({:name => {:first => 'Fred', :last => 'Flinstone'}, :dob => Date.new(DateTime.now.year-34, 2, 4)})
|
47
|
+
template_group = Slippers::TemplateGroup.new(:templates => {:name => Slippers::Engine.new('$first$ $last$'), Date => AgeRenderer.new})
|
48
|
+
engine = Slippers::Engine.new("Introducing $name:name()$ who is $dob$.", :template_group => template_group)
|
49
|
+
engine.render(person) #=> "Introducing Fred Flinstone who is 34 years old."
|
50
|
+
|
51
|
+
8. Use the specified expression options to render list items
|
52
|
+
template = 'This is a list of values $values; null="-1", seperator=", "$'
|
53
|
+
engine = Slippers::Engine.new(template)
|
54
|
+
engine.render(:values => [1,2,3,nil]) #=> "This is a list of values 1, 2, 3, -1"
|
55
|
+
|
56
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
load File.expand_path(File.dirname(__FILE__) + "/tasks/spec.rake")
|
2
|
+
#load File.expand_path(File.dirname(__FILE__) + "/tasks/git.rake")
|
3
|
+
|
4
|
+
require 'rake'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
|
7
|
+
desc "Generate the gem using technicalpickles jeweler"
|
8
|
+
begin
|
9
|
+
require 'jeweler'
|
10
|
+
Jeweler::Tasks.new do |gem|
|
11
|
+
gem.name = "slippers"
|
12
|
+
gem.summary = "A strict templating library for Ruby"
|
13
|
+
gem.email = "me@sarahtaraporewalla.com"
|
14
|
+
gem.homepage = "http://github.com/starapor/slippers"
|
15
|
+
gem.description = "A strict templating library for ruby"
|
16
|
+
gem.authors = ["Sarah Taraporewalla"]
|
17
|
+
gem.files = FileList["[A-Z]*", "{bin,lib,spec,examples}/**/*"]
|
18
|
+
gem.add_dependency 'schacon-git'
|
19
|
+
gem.add_dependency 'treetop'
|
20
|
+
end
|
21
|
+
Jeweler::GemcutterTasks.new
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler"
|
24
|
+
end
|
25
|
+
|
26
|
+
task :default => "spec:run"
|
27
|
+
|
data/VERSION.yml
ADDED
Binary file
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class MainController < Ramaze::Controller
|
2
|
+
layout '/layout'
|
3
|
+
engine :Slippers
|
4
|
+
|
5
|
+
def index
|
6
|
+
@entries = Entry.order(:created.desc).all
|
7
|
+
end
|
8
|
+
|
9
|
+
def delete id
|
10
|
+
entry = Entry[id]
|
11
|
+
entry.delete
|
12
|
+
redirect :/
|
13
|
+
end
|
14
|
+
|
15
|
+
def edit id
|
16
|
+
@entry = Entry[id]
|
17
|
+
redirect_referrer unless @entry
|
18
|
+
end
|
19
|
+
|
20
|
+
def create
|
21
|
+
Entry.add(*request[:title, :content])
|
22
|
+
redirect :/
|
23
|
+
end
|
24
|
+
|
25
|
+
def save
|
26
|
+
redirect_referer unless entry = Entry[request[:id]]
|
27
|
+
entry.update(*request[:title, :content])
|
28
|
+
redirect :/
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
Sequel::Model.plugin(:schema)
|
3
|
+
|
4
|
+
DB = Sequel.connect("sqlite:///#{__DIR__}/../blog.db")
|
5
|
+
|
6
|
+
class Entry < Sequel::Model(:entry)
|
7
|
+
set_schema do
|
8
|
+
primary_key :id
|
9
|
+
|
10
|
+
time :created
|
11
|
+
time :updated
|
12
|
+
text :title
|
13
|
+
text :content
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.add(title, content)
|
17
|
+
create :title => title, :content => content,
|
18
|
+
:created => Time.now, :updated => Time.now
|
19
|
+
end
|
20
|
+
|
21
|
+
def update(title = title, content = content)
|
22
|
+
self.title, self.content, self.updated = title, content, Time.now
|
23
|
+
save
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Entry.create_table! unless Entry.table_exists?
|
28
|
+
|
29
|
+
if Entry.empty?
|
30
|
+
Entry.add 'Blog created', 'Exciting news today, this blog was created'
|
31
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
body {
|
2
|
+
margin: 0;
|
3
|
+
padding: 0;
|
4
|
+
}
|
5
|
+
|
6
|
+
h1 {
|
7
|
+
background: #FFC;
|
8
|
+
margin: 0;
|
9
|
+
padding: 0.25em 3em 0.25em 0.25em;
|
10
|
+
font-size: 32pt;
|
11
|
+
text-align: right;
|
12
|
+
color: #884;
|
13
|
+
border-bottom: 1px solid #004;
|
14
|
+
}
|
15
|
+
|
16
|
+
h2 {
|
17
|
+
margin: 8pt 0 0 0;
|
18
|
+
padding: 0 8pt 4pt 8pt;
|
19
|
+
font-size: 24pt;
|
20
|
+
color: #884;
|
21
|
+
}
|
22
|
+
|
23
|
+
div#actions {
|
24
|
+
margin: -1px 8pt 0 0;
|
25
|
+
padding: 2pt 8pt 4pt 8pt;
|
26
|
+
float: right;
|
27
|
+
background: #FFC;
|
28
|
+
border-style: solid;
|
29
|
+
border-width: 0 2px 2px 1px;
|
30
|
+
border-color: 0 #004 #004 #448;
|
31
|
+
font-size: 10pt;
|
32
|
+
color: #884;
|
33
|
+
}
|
34
|
+
|
35
|
+
div#actions a {
|
36
|
+
color: inherit;
|
37
|
+
text-decoration: none;
|
38
|
+
}
|
39
|
+
|
40
|
+
div#actions a:hover {
|
41
|
+
color: black;
|
42
|
+
}
|
43
|
+
|
44
|
+
div#entries {
|
45
|
+
margin: 0pt 20pt 10pt 12pt;
|
46
|
+
}
|
47
|
+
|
48
|
+
div.entry {
|
49
|
+
margin: 10pt 0 0 0;
|
50
|
+
padding: 0;
|
51
|
+
background-color: #FFD;
|
52
|
+
border-left: 8pt solid #CC8;
|
53
|
+
border-top: 1px solid #CC8;
|
54
|
+
}
|
55
|
+
|
56
|
+
div.entry div.header {
|
57
|
+
background-color: #EEA;
|
58
|
+
border-bottom: 1px solid #CC8;
|
59
|
+
}
|
60
|
+
|
61
|
+
div.entry div.header div.title {
|
62
|
+
font-size: 18pt;
|
63
|
+
color: black;
|
64
|
+
padding: 2pt 4pt 2pt 4pt;
|
65
|
+
}
|
66
|
+
|
67
|
+
div.entry div.header div.title input {
|
68
|
+
width: 100%;
|
69
|
+
border: none;
|
70
|
+
font-size: inherit;
|
71
|
+
}
|
72
|
+
|
73
|
+
div.entry div.header ul {
|
74
|
+
float: left;
|
75
|
+
margin: 0;
|
76
|
+
padding: 0;
|
77
|
+
}
|
78
|
+
|
79
|
+
div.entry div.header ul li {
|
80
|
+
background-color: #EEA;
|
81
|
+
margin: 0 0 0 4pt;
|
82
|
+
padding: 0 4pt 0 4pt;
|
83
|
+
display: inline;
|
84
|
+
border-style: none solid solid solid;
|
85
|
+
border-width: 1px;
|
86
|
+
border-color: #CC8;
|
87
|
+
font-size: 9pt;
|
88
|
+
color: #884;
|
89
|
+
}
|
90
|
+
|
91
|
+
div.entry div.header ul li:hover {
|
92
|
+
color: black;
|
93
|
+
}
|
94
|
+
|
95
|
+
div.entry div.header ul li a {
|
96
|
+
text-decoration: none;
|
97
|
+
color: inherit;
|
98
|
+
}
|
99
|
+
|
100
|
+
div.entry div.header div.created {
|
101
|
+
float: right;
|
102
|
+
font-size: 8pt;
|
103
|
+
color: #888;
|
104
|
+
margin: 0.25em 0.5em 0 0;
|
105
|
+
}
|
106
|
+
|
107
|
+
div.entry div.content {
|
108
|
+
padding: 24pt 16pt 16pt 16pt;
|
109
|
+
border-bottom: 1px solid #CC8;
|
110
|
+
}
|
111
|
+
|
112
|
+
div.entry div.content textarea {
|
113
|
+
width: 100%;
|
114
|
+
border: none;
|
115
|
+
font-size: inherit;
|
116
|
+
height: 12em;
|
117
|
+
margin: -16pt -8pt -8pt -8pt;
|
118
|
+
padding: 8pt;
|
119
|
+
}
|
120
|
+
|
121
|
+
div.entry input[type=submit] {
|
122
|
+
margin: 4pt 16pt 4pt 4pt;
|
123
|
+
border: 1px solid #CC8;
|
124
|
+
background-color: #EEC;
|
125
|
+
}
|
126
|
+
|
127
|
+
div.entry div.updated {
|
128
|
+
float: right;
|
129
|
+
font-size: 8pt;
|
130
|
+
color: #888;
|
131
|
+
margin: -1.25em 0.5em 0 0;
|
132
|
+
}
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'ramaze'
|
2
|
+
require 'ramaze/spec/helper'
|
3
|
+
|
4
|
+
spec_require 'hpricot', 'sequel'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift base = __DIR__('..')
|
7
|
+
require 'start'
|
8
|
+
|
9
|
+
describe 'Blog' do
|
10
|
+
behaves_like 'http'
|
11
|
+
ramaze :public_root => base/:public,
|
12
|
+
:view_root => base/:view
|
13
|
+
|
14
|
+
after do
|
15
|
+
Entry.each{|e| e.delete unless e.id == 1 }
|
16
|
+
end
|
17
|
+
|
18
|
+
def check_page(name = '')
|
19
|
+
page = get("/#{name}")
|
20
|
+
page.status.should == 200
|
21
|
+
page.body.should.not == nil
|
22
|
+
|
23
|
+
doc = Hpricot(page.body)
|
24
|
+
doc.at('title').inner_html.should == 'Blog'
|
25
|
+
doc.at('h1').inner_html.should == 'Blog'
|
26
|
+
|
27
|
+
doc.search('div#entries').size.should == 1
|
28
|
+
|
29
|
+
doc
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_page(title,content)
|
33
|
+
page = post('/create','title'=>title,'content'=>content)
|
34
|
+
page.status.should == 302
|
35
|
+
page.location.should == '/'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should have main page' do
|
39
|
+
doc = check_page
|
40
|
+
doc.at('div#actions>a').inner_html.should == 'new entry'
|
41
|
+
doc.search('div.entry').size.should == 1
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should have new entry page' do
|
45
|
+
doc = check_page('new')
|
46
|
+
form = doc.at('div.entry>form')
|
47
|
+
form.at('input[@name=title]')['value'].should == ''
|
48
|
+
form.at('textarea').inner_html.should == ''
|
49
|
+
form.at('input[@type=submit]')['value'].should == 'Add Entry'
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should add new pages' do
|
53
|
+
create_page('new page', 'cool! a new page')
|
54
|
+
doc = check_page
|
55
|
+
entry = doc.search('div.entry')
|
56
|
+
entry.size.should == 2
|
57
|
+
entry = entry.last
|
58
|
+
|
59
|
+
entry.at('div.title').inner_html == 'new page'
|
60
|
+
entry.at('div.content').inner_html == 'cool! a new page'
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should edit existing pages' do
|
64
|
+
create_page('new page', 'cool! a new page')
|
65
|
+
post('/save','id'=>'2','title'=>'new title','content'=>'bla bla')
|
66
|
+
doc = check_page
|
67
|
+
entries = doc/'div.entry'
|
68
|
+
entries.size.should == 2
|
69
|
+
entry = entries.first
|
70
|
+
|
71
|
+
entry.at('div.title').inner_html == 'new title'
|
72
|
+
entry.at('div.content').inner_html == 'bla bla'
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should delete existing pages' do
|
76
|
+
create_page("page to delete", 'content')
|
77
|
+
entries = check_page/'div.entry'
|
78
|
+
entries.size.should == 2
|
79
|
+
delete_link = entries.last.at("a:contains('delete')")
|
80
|
+
page = get(delete_link[:href])
|
81
|
+
page.status.should == 302
|
82
|
+
page.location.should == '/'
|
83
|
+
(check_page/'div.entry').size.should == 1
|
84
|
+
end
|
85
|
+
|
86
|
+
FileUtils.rm_f(__DIR__('../blog.db'))
|
87
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<h2>Editing entry</h2>
|
2
|
+
<div id="entries">
|
3
|
+
<div class="entry">
|
4
|
+
$entry:{
|
5
|
+
<form method="post" action="/save">
|
6
|
+
<input name="id" type="hidden" value="$id$"/>
|
7
|
+
<div class="header">
|
8
|
+
<div class="title">
|
9
|
+
<input name="title" type="text" value="$title$"/>
|
10
|
+
</div>
|
11
|
+
</div>
|
12
|
+
<div class="content">
|
13
|
+
<textarea name="content">$content$</textarea>
|
14
|
+
</div>
|
15
|
+
<input type="submit" value="Update Entry"/>
|
16
|
+
</form>
|
17
|
+
}$
|
18
|
+
</div>
|
19
|
+
</div>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<h2>Editing entry</h2>
|
2
|
+
<div id="entries">
|
3
|
+
<div class="entry">
|
4
|
+
<form method="post" action="#{R self,:save}">
|
5
|
+
<input name="id" type="hidden" value="#{@entry.id}"/>
|
6
|
+
<div class="header">
|
7
|
+
<div class="title">
|
8
|
+
<input name="title" type="text" value="#{@entry.title}"/>
|
9
|
+
</div>
|
10
|
+
</div>
|
11
|
+
<div class="content">
|
12
|
+
<textarea name="content">#{@entry.content}</textarea>
|
13
|
+
</div>
|
14
|
+
<input type="submit" value="Update Entry"/>
|
15
|
+
</form>
|
16
|
+
</div>
|
17
|
+
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div class="entry">
|
2
|
+
<div class="header">
|
3
|
+
<div class="title">$title$</div>
|
4
|
+
<div class="created">Created: $created$</div>
|
5
|
+
<ul>
|
6
|
+
<li><a href='/edit/$id$'>edit</a></li>
|
7
|
+
<li><a href='/delete/$id$'>delete</a></li>
|
8
|
+
</ul>
|
9
|
+
</div>
|
10
|
+
<div class="content">$content$</div>
|
11
|
+
<div class="updated">Last updated: $updated$</div>
|
12
|
+
</div>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<div id="actions">#{A 'new entry', :href => Rs(:new)}</div>
|
2
|
+
<div id="entries">
|
3
|
+
<?r @entries.each do |entry| ?>
|
4
|
+
<div class="entry">
|
5
|
+
<div class="header">
|
6
|
+
<div class="title">#{entry.title}</div>
|
7
|
+
<div class="created">Created: #{entry.created}</div>
|
8
|
+
<ul>
|
9
|
+
<li>#{A 'edit', :href => Rs(:edit, entry.id)}</li>
|
10
|
+
<li>#{A 'delete', :href => Rs(:delete, entry.id)}</li>
|
11
|
+
</ul>
|
12
|
+
</div>
|
13
|
+
<div class="content">#{entry.content}</div>
|
14
|
+
<div class="updated">Last updated: #{entry.updated}</div>
|
15
|
+
</div>
|
16
|
+
<?r end ?>
|
17
|
+
</div>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<h2>New entry</h2>
|
2
|
+
<div id="entries">
|
3
|
+
<div class="entry">
|
4
|
+
<form method="post" action="/create">
|
5
|
+
<div class="header">
|
6
|
+
<div class="title">
|
7
|
+
<input name="title" type="text" value=""/>
|
8
|
+
</div>
|
9
|
+
</div>
|
10
|
+
<div class="content">
|
11
|
+
<textarea name="content"></textarea>
|
12
|
+
</div>
|
13
|
+
<input type="submit" value="Add Entry"/>
|
14
|
+
</form>
|
15
|
+
</div>
|
16
|
+
</div>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<h2>New entry</h2>
|
2
|
+
<div id="entries">
|
3
|
+
<div class="entry">
|
4
|
+
<form method="post" action="#{R self,:create}">
|
5
|
+
<div class="header">
|
6
|
+
<div class="title">
|
7
|
+
<input name="title" type="text" value=""/>
|
8
|
+
</div>
|
9
|
+
</div>
|
10
|
+
<div class="content">
|
11
|
+
<textarea name="content"></textarea>
|
12
|
+
</div>
|
13
|
+
<input type="submit" value="Add Entry"/>
|
14
|
+
</form>
|
15
|
+
</div>
|
16
|
+
</div>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
desc "Run all examples"
|
5
|
+
Spec::Rake::SpecTask.new('examples') do |t|
|
6
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'spec/rake/spectask'
|
10
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
11
|
+
t.libs << 'lib' << 'spec'
|
12
|
+
t.spec_files = FileList['spec/**/*.rb']
|
13
|
+
end
|
14
|
+
|
15
|
+
Spec::Rake::SpecTask.new(:rcov) do |t|
|
16
|
+
t.libs << 'lib' << 'spec'
|
17
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
18
|
+
t.rcov = true
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
task :default => :examples
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Define a subclass of Ramaze::Controller holding your defaults for all
|
2
|
+
# controllers
|
3
|
+
|
4
|
+
class Controller < Ramaze::Controller
|
5
|
+
layout '/page'
|
6
|
+
helper :xhtml
|
7
|
+
engine :Slippers
|
8
|
+
end
|
9
|
+
|
10
|
+
# Here go your requires for subclasses of Controller:
|
11
|
+
require 'controller/main'
|
12
|
+
require 'controller/registration'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Default url mappings are:
|
2
|
+
# a controller called Main is mapped on the root of the site: /
|
3
|
+
# a controller called Something is mapped on: /something
|
4
|
+
# If you want to override this, add a line like this inside the class
|
5
|
+
# map '/otherurl'
|
6
|
+
# this will force the controller to be mounted on: /otherurl
|
7
|
+
|
8
|
+
class MainController < Controller
|
9
|
+
# the index action is called automatically when no other action is specified
|
10
|
+
def index
|
11
|
+
@title = "Welcome to Ramaze!"
|
12
|
+
end
|
13
|
+
|
14
|
+
# the string returned at the end of the function is used as the html body
|
15
|
+
# if there is no template for the action. if there is a template, the string
|
16
|
+
# is silently ignored
|
17
|
+
def notemplate
|
18
|
+
"there is no 'notemplate.xhtml' associated with this action"
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class RegistrationController < Controller
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
@registrationRepository = RegistrationRepository.new
|
5
|
+
@registrationValidator = RegistrationValidator.new
|
6
|
+
end
|
7
|
+
def index
|
8
|
+
key = request[:key]
|
9
|
+
@form = @registrationRepository.find(key)
|
10
|
+
@message = flash[:message] if flash[:message]
|
11
|
+
end
|
12
|
+
|
13
|
+
def save
|
14
|
+
key=request[:key]
|
15
|
+
form = @registrationRepository.find(key)
|
16
|
+
form.update(:name => request[:name], :address => request[:address], :email => request[:email], :phone => request[:phone])
|
17
|
+
|
18
|
+
@registrationValidator.validate(form)
|
19
|
+
|
20
|
+
@registrationRepository.save(form)
|
21
|
+
flash[:message] = "Saved!"
|
22
|
+
redirect route('/registration', :index, :key=>form[:key])
|
23
|
+
end
|
24
|
+
end
|
Binary file
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Field
|
2
|
+
|
3
|
+
def initialize(key, value)
|
4
|
+
@key = key
|
5
|
+
@value = value
|
6
|
+
@errors = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def update(value)
|
10
|
+
@value = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def value
|
14
|
+
@value
|
15
|
+
end
|
16
|
+
|
17
|
+
def is?(key)
|
18
|
+
@key == key
|
19
|
+
end
|
20
|
+
|
21
|
+
def is_valid?
|
22
|
+
@errors.empty?
|
23
|
+
end
|
24
|
+
|
25
|
+
def invalid(error)
|
26
|
+
@errors << error
|
27
|
+
end
|
28
|
+
|
29
|
+
def errors
|
30
|
+
@errors
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|