starapor-slippers 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/LICENSE +20 -0
  2. data/README +35 -0
  3. data/Rakefile +61 -0
  4. data/VERSION.yml +4 -0
  5. data/examples/blog/README +3 -0
  6. data/examples/blog/blog.db +0 -0
  7. data/examples/blog/controller/main.rb +29 -0
  8. data/examples/blog/model/entry.rb +30 -0
  9. data/examples/blog/public/styles/blog.css +132 -0
  10. data/examples/blog/spec/blog.rb +87 -0
  11. data/examples/blog/start.rb +7 -0
  12. data/examples/blog/view/edit.st +17 -0
  13. data/examples/blog/view/edit.xhtml +17 -0
  14. data/examples/blog/view/entry.st +12 -0
  15. data/examples/blog/view/index.st +4 -0
  16. data/examples/blog/view/index.xhtml +17 -0
  17. data/examples/blog/view/layout.st +11 -0
  18. data/examples/blog/view/layout.xhtml +11 -0
  19. data/examples/blog/view/new.st +16 -0
  20. data/examples/blog/view/new.xhtml +16 -0
  21. data/examples/main_controller.rb +16 -0
  22. data/examples/start.rb +7 -0
  23. data/examples/todolist/README +1 -0
  24. data/examples/todolist/public/favicon.ico +0 -0
  25. data/examples/todolist/public/js/jquery.js +1923 -0
  26. data/examples/todolist/public/ramaze.png +0 -0
  27. data/examples/todolist/spec/todolist.rb +133 -0
  28. data/examples/todolist/src/controller/main.rb +71 -0
  29. data/examples/todolist/src/element/page.rb +31 -0
  30. data/examples/todolist/src/model.rb +14 -0
  31. data/examples/todolist/start.rb +11 -0
  32. data/examples/todolist/template/index.st +39 -0
  33. data/examples/todolist/template/index.xhtml +17 -0
  34. data/examples/todolist/template/new.st +41 -0
  35. data/examples/todolist/template/new.xhtml +7 -0
  36. data/examples/todolist/template/tasks.st +6 -0
  37. data/examples/todolist/todolist.db +7 -0
  38. data/examples/todolist.db +5 -0
  39. data/examples/view/index.st +8 -0
  40. data/examples/view/person/age.st +1 -0
  41. data/examples/view/person/index.st +2 -0
  42. data/examples/view/person/name.st +1 -0
  43. data/lib/engine/binding_wrapper.rb +10 -0
  44. data/lib/engine/engine.rb +26 -0
  45. data/lib/engine/file_template.rb +12 -0
  46. data/lib/engine/slippers.treetop +109 -0
  47. data/lib/engine/slippers_nodes.rb +90 -0
  48. data/lib/engine/template.rb +17 -0
  49. data/lib/engine/template_group.rb +20 -0
  50. data/lib/engine/template_group_directory.rb +39 -0
  51. data/lib/ramazeTemplates/0001-SarahTaraporewalla-adding-new-template-file-for-sli.patch +25 -0
  52. data/lib/ramazeTemplates/slippers.rb +25 -0
  53. data/lib/slippers.rb +14 -0
  54. data/spec/binding_wrapper.rb +14 -0
  55. data/spec/engine.rb +76 -0
  56. data/spec/file_template.rb +9 -0
  57. data/spec/parser.rb +111 -0
  58. data/spec/person_template.st +1 -0
  59. data/spec/slippers_spec.rb +5 -0
  60. data/spec/spec_helper.rb +14 -0
  61. data/spec/template_group.rb +24 -0
  62. data/spec/template_group_directory.rb +38 -0
  63. data/spec/views/index.st +1 -0
  64. data/spec/views/money.rb +2 -0
  65. data/spec/views/person/age.st +1 -0
  66. data/spec/views/person/date_renderer.rb +5 -0
  67. data/spec/views/person/name.st +1 -0
  68. metadata +151 -0
Binary file
@@ -0,0 +1,133 @@
1
+ require 'rubygems'
2
+ require 'ramaze'
3
+ require 'ramaze/spec/helper'
4
+
5
+ spec_require 'hpricot'
6
+
7
+ $LOAD_PATH.unshift base = __DIR__('..')
8
+ require 'start'
9
+
10
+ describe 'todolist' do
11
+ behaves_like 'http'
12
+
13
+ def h_get(*args)
14
+ Hpricot(get(*args).body)
15
+ end
16
+
17
+ def task_titles
18
+ doc = h_get('/')
19
+ doc.search("td[@class='title']").
20
+ map{|t| t.inner_html.strip}.sort
21
+ end
22
+
23
+ def tasks
24
+ (h_get('/')/:tr)
25
+ end
26
+
27
+ def task(name)
28
+ tasks.find do |task|
29
+ (task/:td).find do |td|
30
+ td['class'] == 'title' and
31
+ td.inner_html.strip == name
32
+ end
33
+ end
34
+ end
35
+
36
+ def spectask
37
+ task('spectask')
38
+ end
39
+
40
+ def spectask_status
41
+ spectask.search("td[@class='status']").inner_html.strip
42
+ end
43
+
44
+ def error_on_page(url, response)
45
+ doc = h_get(url, :cookie => response.headers['Set-Cookie'])
46
+
47
+ error = doc.search("div[@class='error']")
48
+ error.inner_html.strip
49
+ end
50
+
51
+ it 'should start' do
52
+ ramaze :public_root => base/:public,
53
+ :view_root => base/:template
54
+ get('/').status.should == 200
55
+ end
56
+
57
+ it 'should have no empty mainpage' do
58
+ get('/').body.should.not == nil
59
+ end
60
+
61
+ it 'should have two preset tasks' do
62
+ task_titles.should == %w[Laundry Wash\ dishes]
63
+ end
64
+
65
+ it 'should have a link to new tasks' do
66
+ doc = h_get('/')
67
+ link = (doc/:a).find{|a| a.inner_html == 'New Task'}
68
+ link['href'].should == '/new'
69
+ end
70
+
71
+ it 'should have a page to create new tasks' do
72
+ get('/new').body.should.not == nil
73
+ end
74
+
75
+ it 'should have a form to create a tasks on the /new page' do
76
+ doc = h_get('/new')
77
+ form = doc.at :form
78
+ form.should.not == nil
79
+ input = form.at(:input)
80
+ input['type'].should == 'text'
81
+ input['name'].should == 'title'
82
+ end
83
+
84
+ it 'should POST new task and redirect to /' do
85
+ result = post('/create', 'title' => 'spectask')
86
+ result.status.should == 302
87
+ end
88
+
89
+ it 'should show have the new task' do
90
+ task_titles.should.include('spectask')
91
+ end
92
+
93
+ it 'should toggle the spectask' do
94
+ get('/close/spectask').status.should == 302
95
+ spectask.should.not == nil
96
+ spectask_status.should == 'done'
97
+ get('/open/spectask').status.should == 302
98
+ spectask.should.not == nil
99
+ spectask_status.should == 'not done'
100
+ end
101
+
102
+ it 'should raise on modifying a not existing task' do
103
+ %w[open close].each do |action|
104
+ response = get("/#{action}/nothere", :referrer => "/")
105
+ response.status.should == 302
106
+ response.original_headers['Location'].should == '/'
107
+ error_on_page('/', response).should == "No such Task: `nothere'"
108
+ end
109
+ end
110
+
111
+ it 'should delete the new task' do
112
+ get('/delete/spectask').status.should == 302
113
+ task_titles.should.not.include('spectask')
114
+ end
115
+
116
+ it 'should not create empty tasks but show a subtle error message' do
117
+ response = post('/create', 'title' => '', :referrer => "/new")
118
+
119
+ response.status.should == 302
120
+ response.original_headers['Location'].should == '/new'
121
+
122
+ error_on_page('/new', response).should == 'Please enter a title'
123
+ end
124
+
125
+ it 'should escape harmful titles' do
126
+ response = post('/create', 'title' => '#{puts "gotcha"}')
127
+
128
+ task('#{puts "gotcha"}').should.be.nil
129
+ task('#{puts "gotcha"}').should.not.be.nil
130
+ end
131
+
132
+ FileUtils.rm('todolist.db') rescue nil
133
+ end
@@ -0,0 +1,71 @@
1
+ # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ # Default url mappings are:
5
+ # a controller called Main is mapped on the root of the site: /
6
+ # a controller called Something is mapped on: /something
7
+ # If you want to override this, add a line like this inside the class
8
+ # map '/otherurl'
9
+ # this will force the controller to be mounted on: /otherurl
10
+
11
+ class MainController < Ramaze::Controller
12
+ engine :Slippers
13
+ def index
14
+ @tasks = []
15
+ TodoList.original.each do |title, value|
16
+ if value[:done]
17
+ status = 'done'
18
+ toggle = 'open'
19
+ else
20
+ status = 'not done'
21
+ toggle = 'close'
22
+ end
23
+ delete = A('Delete', :href => Rs(:delete, title))
24
+ @tasks << {:title => title, :status => status, :resource => title, :toggle => toggle}
25
+ end
26
+ @heading = "TodoList"
27
+ #@tasks.sort!
28
+ end
29
+
30
+ def create
31
+ if title = request['title']
32
+ title.strip!
33
+ if title.empty?
34
+ failed("Please enter a title")
35
+ redirect '/new'
36
+ end
37
+ TodoList[title] = {:done => false}
38
+ end
39
+ end
40
+
41
+ def open title
42
+ task_status title, false
43
+ end
44
+
45
+ def close title
46
+ task_status title, true
47
+ end
48
+
49
+ def delete title
50
+ TodoList.delete title
51
+ end
52
+
53
+ helper :aspect
54
+ after(:create, :open, :close, :delete){ redirect(Rs()) unless redirected? }
55
+
56
+ private
57
+
58
+ def failed(message)
59
+ flash[:error] = message
60
+ end
61
+
62
+ def task_status title, status
63
+ unless task = TodoList[title]
64
+ failed "No such Task: `#{title}'"
65
+ redirect_referer
66
+ end
67
+
68
+ task[:done] = status
69
+ TodoList[title] = task
70
+ end
71
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ class Page < Ezamar::Element
5
+ def render
6
+ %{
7
+ <html>
8
+ <head>
9
+ <title>TodoList</title>
10
+ <style>
11
+ table { width: 100%; }
12
+ tr { background: #efe; width: 100%; }
13
+ tr:hover { background: #dfd; }
14
+ td.title { font-weight: bold; width: 60%; }
15
+ td.status { margin: 1em; }
16
+ a { color: #3a3; }
17
+ </style>
18
+ </head>
19
+ <body>
20
+ <h1>#{@title}</h1>
21
+ <?r if flash[:error] ?>
22
+ <div class="error">
23
+ \#{flash[:error]}
24
+ </div>
25
+ <?r end ?>
26
+ #{content}
27
+ </body>
28
+ </html>
29
+ }
30
+ end
31
+ end
@@ -0,0 +1,14 @@
1
+ # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ require 'ramaze/store/default'
5
+
6
+ TodoList = Ramaze::Store::Default.new('todolist.db')
7
+
8
+ {
9
+ 'Laundry' => {:done => false},
10
+ 'Wash dishes' => {:done => false},
11
+
12
+ }.each do |title, value|
13
+ TodoList[title] = value
14
+ end
@@ -0,0 +1,11 @@
1
+ # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ require 'rubygems'
5
+ require 'ramaze'
6
+
7
+ require 'src/controller/main'
8
+ require 'src/element/page'
9
+ require 'src/model'
10
+
11
+ Ramaze.start :port => 3000
@@ -0,0 +1,39 @@
1
+ <html>
2
+ <head>
3
+ <title>TodoList</title>
4
+ <style>
5
+ table {
6
+ width: 100%;
7
+ }
8
+
9
+ tr {
10
+ background: #efe;
11
+ width: 100%;
12
+ }
13
+
14
+ tr:hover {
15
+ background: #dfd;
16
+ }
17
+
18
+ td.title {
19
+ font-weight: bold;
20
+ width: 60%;
21
+ }
22
+
23
+ td.status {
24
+ margin: 1em;
25
+ }
26
+
27
+ a {
28
+ color: #3a3;
29
+ }
30
+ </style>
31
+ </head>
32
+ <body>
33
+ <h1>$heading$</h1>
34
+ <a href="/new">New Task</a>
35
+ <table>
36
+ $tasks:tasks()$
37
+ </table>
38
+ </body>
39
+ </html>
@@ -0,0 +1,17 @@
1
+ <Page title="TodoList">
2
+ <a href="/new">New Task</a>
3
+ <?r if @tasks.empty? ?>
4
+ No Tasks
5
+ <?r else ?>
6
+ <table>
7
+ <?r @tasks.each do |title, status, toggle, delete| ?>
8
+ <tr>
9
+ <td class="title"> #{h title} </td>
10
+ <td class="status"> #{status} </td>
11
+ <td class="toggle"> #{toggle} </td>
12
+ <td class="delete"> #{delete} </td>
13
+ </tr>
14
+ <?r end ?>
15
+ </table>
16
+ <?r end ?>
17
+ </Page>
@@ -0,0 +1,41 @@
1
+ <html>
2
+ <head>
3
+ <title>TodoList</title>
4
+ <style>
5
+ table {
6
+ width: 100%;
7
+ }
8
+
9
+ tr {
10
+ background: #efe;
11
+ width: 100%;
12
+ }
13
+
14
+ tr:hover {
15
+ background: #dfd;
16
+ }
17
+
18
+ td.title {
19
+ font-weight: bold;
20
+ width: 60%;
21
+ }
22
+
23
+ td.status {
24
+ margin: 1em;
25
+ }
26
+
27
+ a {
28
+ color: #3a3;
29
+ }
30
+ </style>
31
+ </head>
32
+ <body>
33
+ <h1>New Task</h1>
34
+ <a href="/">Back to TodoList</a>
35
+ <form method="POST" action="create">
36
+ Task: <input type="text" name="title" /><br />
37
+ <input type="submit" />
38
+ </form>
39
+
40
+ </body>
41
+ </html>
@@ -0,0 +1,7 @@
1
+ <Page title="New Task">
2
+ <a href="/">Back to TodoList</a>
3
+ <form method="POST" action="create">
4
+ Task: <input type="text" name="title" /><br />
5
+ <input type="submit" />
6
+ </form>
7
+ </Page>
@@ -0,0 +1,6 @@
1
+ <tr>
2
+ <td class="title">$title$</td>
3
+ <td class="status">$status$</td>
4
+ <td class="status"><a href="/$toggle$/$resource$">$toggle$ tasks</a></td>
5
+ <td class="status"><a href="/delete/$resource$">delete</a></td>
6
+ </tr>
@@ -0,0 +1,7 @@
1
+ ---
2
+ Wash dishes:
3
+ :done: false
4
+ Watch the tv:
5
+ :done: false
6
+ Laundry:
7
+ :done: false
@@ -0,0 +1,5 @@
1
+ ---
2
+ Wash dishes:
3
+ :done: false
4
+ Laundry:
5
+ :done: false
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <head>
3
+ <title>Slippers</title>
4
+ </head>
5
+ <body>
6
+ $person:person/index()$
7
+ </body>
8
+ </html>
@@ -0,0 +1 @@
1
+ was born in $year$
@@ -0,0 +1,2 @@
1
+ <h3>Introducing....</h3>
2
+ the faboulous <strong>$name$</strong> who $dob:person/age()$
@@ -0,0 +1 @@
1
+ $first$ $last$
@@ -0,0 +1,10 @@
1
+ module Slippers
2
+ class BindingWrapper
3
+ def initialize(bindings)
4
+ @bindings = bindings
5
+ end
6
+ def [](method)
7
+ eval('@'+ method.to_s, @bindings) || super
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ Treetop.load File.dirname(__FILE__) + '/slippers'
2
+
3
+ module Slippers
4
+ class Engine
5
+
6
+ def initialize(template, params={})
7
+ @main_template = Slippers::Template.new(template)
8
+ @template_group = params[:template_group]
9
+ end
10
+ attr_reader :main_template, :template_group
11
+
12
+ def render(object_to_render=nil)
13
+ parser = SlippersParser.new
14
+ parser.parse(@main_template.template).eval(object_to_render, @template_group)
15
+ end
16
+
17
+ def eql?(other)
18
+ @main_template.eql?(other.main_template) && @template_group.eql?(other.template_group)
19
+ end
20
+
21
+ def hash
22
+ @main_template.hash + @template_group.hash*23
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ module Slippers
2
+ class FileTemplate < Template
3
+ def initialize(filename)
4
+ @filename = filename
5
+ end
6
+ attr_reader :filename
7
+ def template()
8
+ return @template if @template
9
+ @template = File.read(@filename)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,109 @@
1
+ grammar Slippers
2
+
3
+ rule expression
4
+ before:some_text templated_expression space after:expression <ExpressionNode> / some_text
5
+ end
6
+
7
+ rule templated_expression
8
+ "$" foo "$" <TemplatedExpressionNode>
9
+ end
10
+
11
+ rule foo
12
+ apply_attribute_to_template / template / attribute
13
+ end
14
+
15
+ rule apply_attribute_to_template
16
+ attribute apply_op template <ApplyAttributeToTemplateNode>
17
+ end
18
+
19
+ rule template
20
+ known_template / anonymous_template
21
+ end
22
+
23
+ rule known_template
24
+ template_path "()" <TemplateNode>
25
+ end
26
+
27
+ rule anonymous_template
28
+ "{" anonymous_template_words "}" <AnonymousTemplateNode>
29
+ end
30
+
31
+ rule attribute
32
+ word <AttributeNode>
33
+ end
34
+
35
+ rule some_text
36
+ not_delimiter* {
37
+ def eval(*args)
38
+ to_s
39
+ end
40
+ def to_s
41
+ text_value
42
+ end
43
+ }
44
+ end
45
+
46
+ rule not_delimiter
47
+ !"$" . {
48
+ def to_s
49
+ text_value
50
+ end
51
+ }
52
+ end
53
+
54
+ rule anonymous_template_words
55
+ not_curly* {
56
+ def to_s
57
+ text_value
58
+ end
59
+ }
60
+ end
61
+
62
+ rule template_path
63
+ word_with_underscore ("/" word_with_underscore)? {
64
+ def to_s
65
+ text_value
66
+ end
67
+ }
68
+ end
69
+
70
+ rule word_with_underscore
71
+ word ("_" word)*
72
+ end
73
+
74
+ rule not_curly
75
+ !("{" / "}") . {
76
+ def to_s
77
+ text_value
78
+ end
79
+ }
80
+ end
81
+
82
+ rule word
83
+ [a-zA-Z]+ {
84
+ def to_s
85
+ text_value
86
+ end
87
+ }
88
+ end
89
+
90
+ rule space
91
+ ' '* {
92
+ def eval(object_to_render=nil, template_group=nil)
93
+ to_s
94
+ end
95
+ def to_s
96
+ text_value
97
+ end
98
+ }
99
+ end
100
+
101
+ rule apply_op
102
+ ':' {
103
+ def to_s
104
+ text_value
105
+ end
106
+ }
107
+ end
108
+
109
+ end
@@ -0,0 +1,90 @@
1
+ module Slippers
2
+ module AttributeNode
3
+
4
+ def eval(object_to_render, template_group=nil)
5
+ [object_to_render].flatten.inject('') { |rendered, item| rendered + value_of(item).to_s }
6
+ end
7
+
8
+ def value_of(item)
9
+ return item.send(to_s) if item.respond_to?(to_s)
10
+ return item[to_sym] if item.respond_to?('[]'.to_sym) && item[to_sym]
11
+ ''
12
+ end
13
+
14
+ def to_sym
15
+ text_value.to_sym
16
+ end
17
+
18
+ def to_s
19
+ text_value
20
+ end
21
+
22
+ end
23
+
24
+ class TemplateNode < Treetop::Runtime::SyntaxNode
25
+
26
+ def eval(object_to_render, template_group)
27
+ apply_attribute_to_subtemplate(object_to_render, template_group)
28
+ end
29
+
30
+ def apply_attribute_to_subtemplate(item, template_group)
31
+ return '' unless template_group
32
+ subtemplate = template_group.find(template_path.to_s)
33
+ return '' unless (subtemplate && subtemplate.respond_to?('render'))
34
+ subtemplate.render(item)
35
+ end
36
+
37
+ def to_s
38
+ text_value
39
+ end
40
+ end
41
+
42
+ class AnonymousTemplateNode < Treetop::Runtime::SyntaxNode
43
+
44
+ def eval(object_to_render, template_group)
45
+ apply_attribute_to_subtemplate(object_to_render, template_group)
46
+ end
47
+
48
+ def apply_attribute_to_subtemplate(item, template_group)
49
+ SlippersParser.new.parse(anonymous_template_words.to_s).eval(item, template_group)
50
+ end
51
+
52
+ def to_s
53
+ text_value
54
+ end
55
+ end
56
+
57
+ class ApplyAttributeToTemplateNode < Treetop::Runtime::SyntaxNode
58
+
59
+ def eval(object_to_render, template_group)
60
+ [object_to_render].flatten.inject('') { |rendered, item| rendered + find_attribute_and_render(item, template_group) }
61
+ end
62
+
63
+ def find_attribute_and_render(item, template_group)
64
+ object_to_render = attribute.value_of(item)
65
+ [object_to_render].flatten.inject('') { |rendered, i| rendered + template.apply_attribute_to_subtemplate(i, template_group).to_s }
66
+ end
67
+
68
+
69
+ def to_s
70
+ text_value
71
+ end
72
+
73
+ end
74
+
75
+ class TemplatedExpressionNode < Treetop::Runtime::SyntaxNode
76
+
77
+ def eval(object_to_render, template_group=nil)
78
+ foo.eval(object_to_render, template_group)
79
+ end
80
+
81
+ end
82
+
83
+ class ExpressionNode < Treetop::Runtime::SyntaxNode
84
+
85
+ def eval(object_to_render, template_group=nil)
86
+ before.eval + templated_expression.eval(object_to_render, template_group) + space.eval + after.eval(object_to_render, template_group)
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,17 @@
1
+ module Slippers
2
+ class Template
3
+ def initialize(template)
4
+ @template = template
5
+ end
6
+ attr_reader :template
7
+
8
+ def eql?(other)
9
+ template.eql?(other.template)
10
+ end
11
+
12
+ def hash
13
+ template.hash
14
+ end
15
+
16
+ end
17
+ end