curtain 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +5 -40
- data/Rakefile +2 -1
- data/curtain.gemspec +2 -1
- data/lib/curtain.rb +0 -8
- data/lib/curtain/rendering.rb +31 -7
- data/lib/curtain/version.rb +1 -1
- data/test/curtain_test.rb +66 -0
- data/test/examples/registration.mustache +48 -0
- data/test/examples/simple.erb +1 -0
- data/test/test_helper.rb +1 -1
- metadata +35 -46
- data/lib/curtain/block_helpers.rb +0 -11
- data/lib/curtain/caching.rb +0 -39
- data/lib/curtain/erubis.rb +0 -35
- data/lib/curtain/erubis_template.rb +0 -25
- data/lib/curtain/html_helpers.rb +0 -33
- data/lib/curtain/output_buffer.rb +0 -12
- data/lib/curtain/url_helpers.rb +0 -149
- data/test/caching_test.rb +0 -49
- data/test/examples/cache.erb +0 -3
- data/test/examples/cache.slim +0 -2
- data/test/html_helpers_test.rb +0 -26
- data/test/url_helpers_test.rb +0 -45
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8e1156e5774dba04fd48f55a9ba00b80c7ece79e
|
4
|
+
data.tar.gz: 733abf03c5255f5554bf320cdd7706ab6ce2dac3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d3e1e00778a9f258d8345ea8c369e82f65e6c0ccec4f31b91664b8a516d69d94fd868f69d7b8a1e9ca105cebc23c2a16ae0ffd1aaa5db3cde97ed766150e5d96
|
7
|
+
data.tar.gz: b5f2cd8598ff384ed766c8ce38939802f4f6776a82661379c0e72bf81f4406899125895fb2ee4330fd51b8633e34562f3b70e9f40f63b04d871ee70edd120dd5
|
data/README.md
CHANGED
@@ -29,9 +29,9 @@ To use Curtain, you define a view and then have that view render templates:
|
|
29
29
|
``` ruby
|
30
30
|
class MyView
|
31
31
|
include Curtain
|
32
|
-
|
32
|
+
|
33
33
|
attr_accessor :msg
|
34
|
-
|
34
|
+
|
35
35
|
def initialize(msg)
|
36
36
|
@msg = msg
|
37
37
|
end
|
@@ -55,41 +55,6 @@ There is an equivalent shortcut available:
|
|
55
55
|
Curtain.render("hello", :msg => "Hello, World!")
|
56
56
|
```
|
57
57
|
|
58
|
-
Curtain includes many useful methods. Here's a more realistic example that shows some of the built-in methods. If you have templates like this:
|
59
|
-
|
60
|
-
### friends.erb
|
61
|
-
``` erb
|
62
|
-
<% cache "friends-#{current_user.id}", ttl: 5.minutes do %>
|
63
|
-
<% friends.each do |friend| %>
|
64
|
-
<%= render "profile", :profile => friend %>
|
65
|
-
<% end %>
|
66
|
-
<% end %>
|
67
|
-
```
|
68
|
-
|
69
|
-
### profile.erb
|
70
|
-
``` erb
|
71
|
-
<ul>
|
72
|
-
<li><%= link_to profile.name, path(:profile, :id => profile.id) %></li>
|
73
|
-
</ul>
|
74
|
-
```
|
75
|
-
|
76
|
-
You can use them in this way:
|
77
|
-
|
78
|
-
``` ruby
|
79
|
-
class ApplicationView < Curtain::View
|
80
|
-
attr_accessor :current_user
|
81
|
-
end
|
82
|
-
|
83
|
-
class FriendsView < Curtain::View
|
84
|
-
delegate :friends, :to => :current_user
|
85
|
-
end
|
86
|
-
|
87
|
-
view = FriendsView.new(:current_user => User.first)
|
88
|
-
|
89
|
-
# The default template name is based on the name of the class of the view
|
90
|
-
view.render
|
91
|
-
```
|
92
|
-
|
93
58
|
### Variables
|
94
59
|
|
95
60
|
If you don't want to define a subclass of `Curtain::View` and add attributes to it, you can also use variables. `Curtain::View` supports the hash-like Ruby method `[]` and `[]=` to define variables that will act as locals in when the template is rendered:
|
@@ -104,7 +69,7 @@ view = Curtain::View.new
|
|
104
69
|
view[:msg] = "Hello"
|
105
70
|
view.render(:hello) # => "<h1>Hello</h1>"
|
106
71
|
```
|
107
|
-
|
72
|
+
|
108
73
|
Note that unlike locals, variables exist throughout nested scope of render calls:
|
109
74
|
|
110
75
|
### main.erb
|
@@ -113,14 +78,14 @@ foo: <%= foo %>
|
|
113
78
|
bar: <%= bar %>
|
114
79
|
<%= render "partial" %>
|
115
80
|
```
|
116
|
-
|
81
|
+
|
117
82
|
### partial.erb
|
118
83
|
``` erb
|
119
84
|
foo: <%= foo %>
|
120
85
|
bar: <%= bar %>
|
121
86
|
```
|
122
87
|
|
123
|
-
``` ruby
|
88
|
+
``` ruby
|
124
89
|
class MainView < Curtain::View
|
125
90
|
end
|
126
91
|
|
data/Rakefile
CHANGED
data/curtain.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |gem|
|
|
12
12
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
13
13
|
gem.name = "curtain"
|
14
14
|
gem.require_paths = ["lib"]
|
15
|
-
gem.version = "0.
|
15
|
+
gem.version = "0.2.0"
|
16
16
|
|
17
17
|
gem.add_runtime_dependency "activesupport"
|
18
18
|
gem.add_runtime_dependency "tilt"
|
@@ -20,4 +20,5 @@ Gem::Specification.new do |gem|
|
|
20
20
|
gem.add_development_dependency "erubis"
|
21
21
|
gem.add_development_dependency "haml"
|
22
22
|
gem.add_development_dependency "slim"
|
23
|
+
gem.add_development_dependency "mustache"
|
23
24
|
end
|
data/lib/curtain.rb
CHANGED
@@ -1,11 +1,7 @@
|
|
1
1
|
require 'active_support/core_ext'
|
2
2
|
require 'curtain/templating'
|
3
3
|
require 'curtain/rendering'
|
4
|
-
require 'curtain/block_helpers'
|
5
|
-
require 'curtain/url_helpers'
|
6
|
-
require 'curtain/caching'
|
7
4
|
require 'curtain/variable_support'
|
8
|
-
require 'curtain/html_helpers'
|
9
5
|
require 'curtain/version'
|
10
6
|
|
11
7
|
module Curtain
|
@@ -14,11 +10,7 @@ module Curtain
|
|
14
10
|
cls.class_eval do
|
15
11
|
include Curtain::Templating
|
16
12
|
include Curtain::Rendering
|
17
|
-
include Curtain::BlockHelpers
|
18
|
-
include Curtain::UrlHelpers
|
19
|
-
include Curtain::Caching
|
20
13
|
include Curtain::VariableSupport
|
21
|
-
include Curtain::HTMLHelpers
|
22
14
|
end
|
23
15
|
end
|
24
16
|
|
data/lib/curtain/rendering.rb
CHANGED
@@ -1,6 +1,26 @@
|
|
1
1
|
require 'tilt'
|
2
2
|
|
3
3
|
module Curtain
|
4
|
+
|
5
|
+
class MustacheRenderer < ::Mustache
|
6
|
+
def initialize(view, template_file)
|
7
|
+
@view = view
|
8
|
+
@template_file = template_file
|
9
|
+
end
|
10
|
+
|
11
|
+
def respond_to?(method_name)
|
12
|
+
super || @view.respond_to?(method_name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(name, *args, &block)
|
16
|
+
if @view.respond_to?(name)
|
17
|
+
@view.send(name, *args, &block)
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
4
24
|
module Rendering
|
5
25
|
# Renders the template
|
6
26
|
#
|
@@ -36,14 +56,18 @@ module Curtain
|
|
36
56
|
|
37
57
|
# TODO: Cache Template objects
|
38
58
|
template_file = self.class.find_template(name)
|
59
|
+
ext = template_file.split('.').last
|
39
60
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
61
|
+
# Apparently Tilt doesn't support mustache?
|
62
|
+
# TODO: There has to be an implementation out there,
|
63
|
+
# if not, write one
|
64
|
+
if ext == 'mustache'
|
65
|
+
mustache = MustacheRenderer.new(self, template_file)
|
66
|
+
mustache.render
|
67
|
+
else
|
68
|
+
template = Tilt.new(template_file)
|
69
|
+
template.render(self, variables.merge(locals))
|
70
|
+
end
|
47
71
|
end
|
48
72
|
end
|
49
73
|
end
|
data/lib/curtain/version.rb
CHANGED
data/test/curtain_test.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
puts $:
|
1
2
|
require 'test_helper'
|
2
3
|
|
3
4
|
class CurtainTest < Test::Unit::TestCase
|
@@ -13,6 +14,43 @@ class CurtainTest < Test::Unit::TestCase
|
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
17
|
+
class Account
|
18
|
+
attr_accessor :email, :password, :first_name, :last_name, :gender, :date_of_birth
|
19
|
+
|
20
|
+
def initialize(attrs={})
|
21
|
+
if attrs
|
22
|
+
attrs.each do |attr, value|
|
23
|
+
send("#{attr}=", value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class ::RegistrationView < TestView
|
30
|
+
|
31
|
+
attr_accessor :account, :errors
|
32
|
+
|
33
|
+
delegate :email, :first_name, :last_name, :gender, :date_of_birth, :to => :account
|
34
|
+
|
35
|
+
def date_of_birth_day_options
|
36
|
+
[{}] + (1..31).map do |day|
|
37
|
+
{ text: day, value: day, selected: day == date_of_birth.try(:day) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def date_of_birth_month_options
|
42
|
+
Date::ABBR_MONTHNAMES.each_with_index.map do |month, i|
|
43
|
+
{ text: month, value: i > 0 ? 1 : nil, selected: i == date_of_birth.try(:month) ? 'selected' : nil }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def date_of_birth_year_options
|
48
|
+
[{}] + 13.years.ago.year.downto(113.years.ago.year).map do |year|
|
49
|
+
{ text: year, value: year, selected: year == date_of_birth.try(:year) ? 'selected' : nil }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
16
54
|
class SubdirView < Curtain::View
|
17
55
|
template :index
|
18
56
|
end
|
@@ -50,4 +88,32 @@ class CurtainTest < Test::Unit::TestCase
|
|
50
88
|
assert_equal "<html><body><h1>Hello, World!</h1>\n</body></html>\n", view.render("layout", :main => "body")
|
51
89
|
end
|
52
90
|
|
91
|
+
def test_mustache_form
|
92
|
+
expected = remove_whitespace(%{<h2>Register</h2>
|
93
|
+
<form action="/register">
|
94
|
+
<label class="block">
|
95
|
+
Email:
|
96
|
+
<input type="type" name="email" value="mail@paulbarry.com" />
|
97
|
+
</label>
|
98
|
+
<label class="block">
|
99
|
+
Password:
|
100
|
+
<input type="password" name="password" />
|
101
|
+
</label>
|
102
|
+
<label class="block">
|
103
|
+
First Name:
|
104
|
+
<input type="text" name="first_name" value="" />
|
105
|
+
</label>
|
106
|
+
<button type="submit" class="btn btn-primary">Log In</button>
|
107
|
+
</form>})
|
108
|
+
|
109
|
+
view = RegistrationView.new(account: Account.new(email: 'mail@paulbarry.com', date_of_birth: Date.parse('1978-07-06')))
|
110
|
+
puts view.render
|
111
|
+
assert_equal expected, remove_whitespace(view.render)
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
def remove_whitespace(s)
|
116
|
+
s.to_s.split("\n").map(&:strip).reject(&:blank?).join("\n")
|
117
|
+
end
|
118
|
+
|
53
119
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
<h2>Register</h2>
|
2
|
+
<form action="/register">
|
3
|
+
|
4
|
+
{{#errors}}
|
5
|
+
<div class="error">
|
6
|
+
{{ msg }}
|
7
|
+
</div>
|
8
|
+
{{/errors}}
|
9
|
+
|
10
|
+
<label class="block">
|
11
|
+
Email:
|
12
|
+
<input type="type" name="email" value="{{ email }}" />
|
13
|
+
</label>
|
14
|
+
|
15
|
+
<label class="block">
|
16
|
+
Password:
|
17
|
+
<input type="password" name="password" />
|
18
|
+
</label>
|
19
|
+
|
20
|
+
<label class="block">
|
21
|
+
First Name:
|
22
|
+
<input type="text" name="first_name" value="{{ first_name }}" />
|
23
|
+
</label>
|
24
|
+
|
25
|
+
<label class="block">
|
26
|
+
Date of Birth:
|
27
|
+
|
28
|
+
<select name="date_of_birth[month]">
|
29
|
+
{{#date_of_birth_month_options}}
|
30
|
+
<option value="{{ value }}"{{#selected}} selected="selected"{{/selected}}>{{ text }}</option>
|
31
|
+
{{/date_of_birth_month_options}}
|
32
|
+
</select>
|
33
|
+
|
34
|
+
<select name="date_of_birth[day]">
|
35
|
+
{{#date_of_birth_day_options}}
|
36
|
+
<option value="{{ value }}"{{#selected}} selected="selected"{{/selected}}>{{ text }}</option>
|
37
|
+
{{/date_of_birth_day_options}}
|
38
|
+
</select>
|
39
|
+
|
40
|
+
<select name="date_of_birth[year]">
|
41
|
+
{{#date_of_birth_year_options}}
|
42
|
+
<option value="{{ value }}"{{#selected}} selected="selected"{{/selected}}>{{ text }}</option>
|
43
|
+
{{/date_of_birth_year_options}}
|
44
|
+
</select>
|
45
|
+
</label>
|
46
|
+
|
47
|
+
<button type="submit" class="btn btn-primary">Log In</button>
|
48
|
+
</form>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= msg %>
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,94 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: curtain
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Paul Barry
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-05-30 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: activesupport
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: tilt
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: erubis
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: haml
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - '>='
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: '0'
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - '>='
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: '0'
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: slim
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - '>='
|
84
74
|
- !ruby/object:Gem::Version
|
85
75
|
version: '0'
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- -
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: mustache
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
92
95
|
- !ruby/object:Gem::Version
|
93
96
|
version: '0'
|
94
97
|
description: A template rendering framework
|
@@ -106,64 +109,50 @@ files:
|
|
106
109
|
- Rakefile
|
107
110
|
- curtain.gemspec
|
108
111
|
- lib/curtain.rb
|
109
|
-
- lib/curtain/block_helpers.rb
|
110
|
-
- lib/curtain/caching.rb
|
111
|
-
- lib/curtain/erubis.rb
|
112
|
-
- lib/curtain/erubis_template.rb
|
113
|
-
- lib/curtain/html_helpers.rb
|
114
|
-
- lib/curtain/output_buffer.rb
|
115
112
|
- lib/curtain/rendering.rb
|
116
113
|
- lib/curtain/templating.rb
|
117
|
-
- lib/curtain/url_helpers.rb
|
118
114
|
- lib/curtain/variable_support.rb
|
119
115
|
- lib/curtain/version.rb
|
120
|
-
- test/caching_test.rb
|
121
116
|
- test/curtain_test.rb
|
122
117
|
- test/examples/body.erb
|
123
|
-
- test/examples/cache.erb
|
124
|
-
- test/examples/cache.slim
|
125
118
|
- test/examples/index.erb
|
126
119
|
- test/examples/layout.erb
|
120
|
+
- test/examples/registration.mustache
|
121
|
+
- test/examples/simple.erb
|
127
122
|
- test/examples/subdir/index.erb
|
128
123
|
- test/examples/test.erb
|
129
|
-
- test/html_helpers_test.rb
|
130
124
|
- test/test_helper.rb
|
131
|
-
- test/url_helpers_test.rb
|
132
125
|
homepage: http://github.com/pjb3/curtain
|
133
126
|
licenses: []
|
127
|
+
metadata: {}
|
134
128
|
post_install_message:
|
135
129
|
rdoc_options: []
|
136
130
|
require_paths:
|
137
131
|
- lib
|
138
132
|
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
-
none: false
|
140
133
|
requirements:
|
141
|
-
- -
|
134
|
+
- - '>='
|
142
135
|
- !ruby/object:Gem::Version
|
143
136
|
version: '0'
|
144
137
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
138
|
requirements:
|
147
|
-
- -
|
139
|
+
- - '>='
|
148
140
|
- !ruby/object:Gem::Version
|
149
141
|
version: '0'
|
150
142
|
requirements: []
|
151
143
|
rubyforge_project:
|
152
|
-
rubygems_version:
|
144
|
+
rubygems_version: 2.0.0
|
153
145
|
signing_key:
|
154
|
-
specification_version:
|
146
|
+
specification_version: 4
|
155
147
|
summary: A template rendering framework
|
156
148
|
test_files:
|
157
|
-
- test/caching_test.rb
|
158
149
|
- test/curtain_test.rb
|
159
150
|
- test/examples/body.erb
|
160
|
-
- test/examples/cache.erb
|
161
|
-
- test/examples/cache.slim
|
162
151
|
- test/examples/index.erb
|
163
152
|
- test/examples/layout.erb
|
153
|
+
- test/examples/registration.mustache
|
154
|
+
- test/examples/simple.erb
|
164
155
|
- test/examples/subdir/index.erb
|
165
156
|
- test/examples/test.erb
|
166
|
-
- test/html_helpers_test.rb
|
167
157
|
- test/test_helper.rb
|
168
|
-
- test/url_helpers_test.rb
|
169
158
|
has_rdoc:
|
data/lib/curtain/caching.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
module Curtain
|
2
|
-
class CacheNotSet < RuntimeError; end
|
3
|
-
|
4
|
-
module Caching
|
5
|
-
module ClassMethods
|
6
|
-
def cache(*args)
|
7
|
-
if args.empty?
|
8
|
-
if defined? @cache
|
9
|
-
@cache
|
10
|
-
elsif superclass.respond_to?(:cache)
|
11
|
-
superclass.cache
|
12
|
-
end
|
13
|
-
else
|
14
|
-
self.cache = args.first
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def cache=(cache)
|
19
|
-
@cache = cache
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.included(cls)
|
24
|
-
cls.extend(ClassMethods)
|
25
|
-
end
|
26
|
-
|
27
|
-
def cache(key, ttl=nil, &block)
|
28
|
-
if self.class.cache
|
29
|
-
unless value = self.class.cache.get(key)
|
30
|
-
value = capture(&block)
|
31
|
-
self.class.cache.set(key, value, ttl)
|
32
|
-
end
|
33
|
-
value
|
34
|
-
else
|
35
|
-
raise CacheNotSet.new("Cache not set, set it with Curtain.cache = Cache.new")
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
data/lib/curtain/erubis.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
require 'erubis'
|
2
|
-
require 'curtain'
|
3
|
-
require 'curtain/output_buffer'
|
4
|
-
require 'curtain/erubis_template'
|
5
|
-
|
6
|
-
module Curtain
|
7
|
-
class Erubis < ::Erubis::Eruby
|
8
|
-
def add_text(src, text)
|
9
|
-
return if text.empty?
|
10
|
-
src << "@output_buffer.safe_concat('" << escape_text(text) << "');"
|
11
|
-
end
|
12
|
-
|
13
|
-
BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
14
|
-
|
15
|
-
def add_expr_literal(src, code)
|
16
|
-
if code =~ BLOCK_EXPR
|
17
|
-
src << '@output_buffer.append= ' << code
|
18
|
-
else
|
19
|
-
src << '@output_buffer.append= (' << code << ');'
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def add_expr_escaped(src, code)
|
24
|
-
if code =~ BLOCK_EXPR
|
25
|
-
src << "@output_buffer.safe_append= " << code
|
26
|
-
else
|
27
|
-
src << "@output_buffer.safe_concat((" << code << ").to_s);"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def add_postamble(src)
|
32
|
-
src << '@output_buffer.to_s'
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'tilt'
|
2
|
-
|
3
|
-
module Curtain
|
4
|
-
class ErubisTemplate < Tilt::Template
|
5
|
-
DEFAULT_OUTPUT_VARIABLE = '@output_buffer'
|
6
|
-
|
7
|
-
def self.engine_initialized?
|
8
|
-
defined? ::ERB
|
9
|
-
end
|
10
|
-
|
11
|
-
def initialize_engine
|
12
|
-
require_template_library 'erubis'
|
13
|
-
end
|
14
|
-
|
15
|
-
def prepare
|
16
|
-
@engine = Curtain::Erubis.new(data, options)
|
17
|
-
end
|
18
|
-
|
19
|
-
def precompiled_template(locals)
|
20
|
-
@engine.src
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
Tilt.prefer Curtain::ErubisTemplate, 'erb'
|
data/lib/curtain/html_helpers.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'cgi'
|
2
|
-
|
3
|
-
module Curtain
|
4
|
-
module HTMLHelpers
|
5
|
-
def h(html)
|
6
|
-
CGI::escapeHTML(html)
|
7
|
-
end
|
8
|
-
|
9
|
-
def content_tag(name, attributes_or_body=nil, attributes=nil, &block)
|
10
|
-
result = "<#{name}"
|
11
|
-
|
12
|
-
if attributes_or_body.is_a?(Hash)
|
13
|
-
attributes = attributes_or_body
|
14
|
-
end
|
15
|
-
|
16
|
-
if attributes
|
17
|
-
result << " #{attributes.map{|k,v| %{#{k}="#{h(v)}"} }.join(' ')}>"
|
18
|
-
else
|
19
|
-
result << ">"
|
20
|
-
end
|
21
|
-
|
22
|
-
if block
|
23
|
-
result << capture(&block)
|
24
|
-
elsif !attributes_or_body.is_a?(Hash)
|
25
|
-
result << attributes_or_body.to_s
|
26
|
-
end
|
27
|
-
|
28
|
-
result << "</#{name}>"
|
29
|
-
|
30
|
-
result
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
data/lib/curtain/url_helpers.rb
DELETED
@@ -1,149 +0,0 @@
|
|
1
|
-
module Curtain
|
2
|
-
class NamedRoutesNotSet < RuntimeError; end
|
3
|
-
class UnknownNamedRoute < RuntimeError; end
|
4
|
-
|
5
|
-
module UrlHelpers
|
6
|
-
|
7
|
-
# When a class includes {Curtain::UrlHelpers}, that class also extends
|
8
|
-
# this module, which makes these methods class methods on the class.
|
9
|
-
# These methods act as class-level attributes that accept
|
10
|
-
# a value at any level of a class hierarchy,
|
11
|
-
# using the value set on the specific class if it has one,
|
12
|
-
# otherwise it delegates it's way up the inheritance chain.
|
13
|
-
# The general pattern of these methods is that the getter accepts an
|
14
|
-
# option argument, which sets the value of the attribute.
|
15
|
-
# This style supports a natural DSL-like way of defining the
|
16
|
-
# values for the attribute definition in the class definition
|
17
|
-
#
|
18
|
-
# @example
|
19
|
-
# class MyView
|
20
|
-
# include Curtain::UrlHelpers
|
21
|
-
# default_host "example.com"
|
22
|
-
# end
|
23
|
-
#
|
24
|
-
module ClassMethods
|
25
|
-
|
26
|
-
def named_routes(*args)
|
27
|
-
if args.empty?
|
28
|
-
if defined? @named_routes
|
29
|
-
@named_routes
|
30
|
-
elsif superclass.respond_to?(:named_routes)
|
31
|
-
superclass.named_routes
|
32
|
-
end
|
33
|
-
else
|
34
|
-
self.named_routes = args.first
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def named_routes=(named_routes)
|
39
|
-
@named_routes = named_routes
|
40
|
-
end
|
41
|
-
|
42
|
-
def default_host(*args)
|
43
|
-
if args.empty?
|
44
|
-
if defined? @default_host
|
45
|
-
@default_host
|
46
|
-
elsif superclass.respond_to?(:default_host)
|
47
|
-
superclass.default_host
|
48
|
-
end
|
49
|
-
else
|
50
|
-
self.default_host = args.first
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def default_host=(default_host)
|
55
|
-
@default_host = default_host
|
56
|
-
end
|
57
|
-
|
58
|
-
def default_port(*args)
|
59
|
-
if args.empty?
|
60
|
-
if defined? @default_port
|
61
|
-
@default_port
|
62
|
-
elsif superclass.respond_to?(:default_port)
|
63
|
-
superclass.default_port
|
64
|
-
end
|
65
|
-
else
|
66
|
-
self.default_port = args.first
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def default_port=(default_port)
|
71
|
-
@default_port = default_port
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.included(cls)
|
76
|
-
cls.extend(ClassMethods)
|
77
|
-
end
|
78
|
-
|
79
|
-
# Generates a URL
|
80
|
-
#
|
81
|
-
# @param [String, Symbol] route
|
82
|
-
# If this is a String, this will just use the same value in the path.
|
83
|
-
# If this is a Symbol, the path will be looked up in the named_routes
|
84
|
-
# @param [Hash] options
|
85
|
-
# @option options [String] :scheme
|
86
|
-
# The scheme to use for the URL, defaults to 'http'
|
87
|
-
# @option options [String] :host
|
88
|
-
# The host to use for the URL, uses the class-level attribute
|
89
|
-
# {Curtain::UrlHelpers::ClassMethods#default_host} as the default
|
90
|
-
# @option options [String] :port
|
91
|
-
# The port to use for the URL, uses the class-level attribute
|
92
|
-
# {Curtain::UrlHelpers::ClassMethods#default_host} as the default.
|
93
|
-
# The port is omitted if the scheme is 'http' and the port is 80
|
94
|
-
# or if the scheme is 'https' and the port is 443
|
95
|
-
# @option options [String] :fragment
|
96
|
-
# Sets the fragment portion of the URL, also known as the anchor
|
97
|
-
# @option options [String] :params
|
98
|
-
# A hash of parameters to include in the query string
|
99
|
-
# @return [String] The URL
|
100
|
-
# @example
|
101
|
-
# url("/posts",
|
102
|
-
# :scheme => 'http',
|
103
|
-
# :host => 'foo.com',
|
104
|
-
# :params => { :id => 30, :limit => 5 },
|
105
|
-
# :fragment => "time=1305298413")
|
106
|
-
# # => "http://foo.com/posts?id=30&limit=5#time=1305298413"
|
107
|
-
def url(route, options={})
|
108
|
-
options ||= {}
|
109
|
-
end
|
110
|
-
|
111
|
-
# Generates a relative path
|
112
|
-
#
|
113
|
-
# @param [String, Symbol] route
|
114
|
-
# If this is a String, this will just use the same value in the path.
|
115
|
-
# If this is a Symbol, the path will be looked up in the named_routes
|
116
|
-
def path(route, params={})
|
117
|
-
params ||= {}
|
118
|
-
|
119
|
-
path = case route
|
120
|
-
when String then route.dup
|
121
|
-
when Symbol
|
122
|
-
if self.class.named_routes
|
123
|
-
if p = self.class.named_routes[route]
|
124
|
-
p.dup
|
125
|
-
else
|
126
|
-
raise UnknownNamedRoute.new("Could not find named route for #{route.inspect}")
|
127
|
-
end
|
128
|
-
else
|
129
|
-
raise NamedRoutesNotSet.new("You must setup the named routes like 'Curtain::View.named_routes = {}'")
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
# You are going to need this, this is how you interpolate a params into a route
|
134
|
-
# and get back a subset of params that didn't match a route param
|
135
|
-
query_params = params.inject({}) do |acc,(k,v)|
|
136
|
-
unless path.sub!(/:#{k.to_param}(\/|\?|#|\Z)/,"#{v.to_param}\\1")
|
137
|
-
acc[k] = v
|
138
|
-
end
|
139
|
-
acc
|
140
|
-
end
|
141
|
-
|
142
|
-
if query_params.blank?
|
143
|
-
path
|
144
|
-
else
|
145
|
-
"#{path}?#{query_params.to_query}"
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
data/test/caching_test.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class CurtainTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
class TestCache
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
flush
|
9
|
-
end
|
10
|
-
|
11
|
-
def get(k, opts={})
|
12
|
-
@store[k]
|
13
|
-
end
|
14
|
-
|
15
|
-
def set(k, v, ttl=nil, opts={})
|
16
|
-
@store[k] = v
|
17
|
-
end
|
18
|
-
|
19
|
-
def flush
|
20
|
-
@store = {}
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
class CacheView < Curtain::View
|
26
|
-
cache TestCache.new
|
27
|
-
template_directories File.join(File.dirname(__FILE__), "examples")
|
28
|
-
template :cache
|
29
|
-
end
|
30
|
-
|
31
|
-
def setup
|
32
|
-
CacheView.cache.flush
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_cache_erb
|
36
|
-
view = CacheView.new
|
37
|
-
assert_equal "<h1>foo</h1>", view.render.strip
|
38
|
-
assert_equal "<h1>foo</h1>", view.class.cache.get("foo").strip
|
39
|
-
assert_equal "<h1>foo</h1>", view.render.strip
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_cache_slim
|
43
|
-
view = CacheView.new
|
44
|
-
result = view.render("cache.slim").strip
|
45
|
-
assert_equal "<h1>foo</h1>", view.class.cache.get("foo").strip
|
46
|
-
assert_equal "<h1>foo</h1>", result
|
47
|
-
assert_equal "<h1>foo</h1>", view.render("cache.slim").strip
|
48
|
-
end
|
49
|
-
end
|
data/test/examples/cache.erb
DELETED
data/test/examples/cache.slim
DELETED
data/test/html_helpers_test.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class HTMLHelpersTest < Test::Unit::TestCase
|
4
|
-
include Curtain::BlockHelpers
|
5
|
-
include Curtain::HTMLHelpers
|
6
|
-
|
7
|
-
def test_content_tag_no_body
|
8
|
-
assert_equal "<p></p>", content_tag(:p)
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_content_tag_body
|
12
|
-
assert_equal "<p>foo</p>", content_tag(:p, "foo")
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_content_tag_body_attributes
|
16
|
-
assert_equal %{<p bar="baz">foo</p>}, content_tag(:p, "foo", :bar => "baz")
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_content_tag_no_body_attributes
|
20
|
-
assert_equal %{<p bar="baz"></p>}, content_tag(:p, :bar => "baz")
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_content_tag_block_body_attributes
|
24
|
-
assert_equal(%{<p>foo</p>}, content_tag(:p){ "foo" })
|
25
|
-
end
|
26
|
-
end
|
data/test/url_helpers_test.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class UrlHelpersTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
class TestView < Curtain::View
|
6
|
-
named_routes :home => "/home",
|
7
|
-
:profile => "/profiles/:id",
|
8
|
-
:post => "/:year/:month/:day/:slug"
|
9
|
-
end
|
10
|
-
|
11
|
-
def setup
|
12
|
-
@view = TestView.new
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_path_with_named_route
|
16
|
-
assert_equal "/home", @view.path(:home)
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_path_with_named_route_with_params
|
20
|
-
assert_equal "/home?q=foo", @view.path(:home, :q => "foo")
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_path_with_named_route_with_route_params
|
24
|
-
assert_equal "/profiles/42", @view.path(:profile, :id => 42)
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_path_with_named_route_with_multiple_route_params
|
28
|
-
assert_equal "/2012/10/19/first-post",
|
29
|
-
@view.path(:post,
|
30
|
-
:year => 2012,
|
31
|
-
:month => 10,
|
32
|
-
:day => 19,
|
33
|
-
:slug => "first-post")
|
34
|
-
end
|
35
|
-
|
36
|
-
def test_path_with_named_route_with_multiple_route_params_and_query_params
|
37
|
-
assert_equal "/2012/10/19/first-post?tag=foo",
|
38
|
-
@view.path(:post,
|
39
|
-
:year => 2012,
|
40
|
-
:month => 10,
|
41
|
-
:day => 19,
|
42
|
-
:slug => "first-post",
|
43
|
-
:tag => "foo")
|
44
|
-
end
|
45
|
-
end
|