curtain 0.1.3 → 0.2.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.
- 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
|