starapor-slippers 0.0.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.
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