tiny 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/README.md +388 -0
- data/Rakefile +1 -0
- data/lib/tiny.rb +519 -0
- data/lib/tiny/erubis.rb +63 -0
- data/lib/tiny/html.rb +177 -0
- data/lib/tiny/safe_string.rb +16 -0
- data/lib/tiny/tag.rb +47 -0
- data/lib/tiny/version.rb +3 -0
- data/spec/erubis_spec.rb +48 -0
- data/spec/fixtures/erb_list.erb +20 -0
- data/spec/fixtures/erb_list_with_helpers.erb +5 -0
- data/spec/fixtures/haml_list.haml +16 -0
- data/spec/fixtures/haml_list_with_helpers.haml +4 -0
- data/spec/helpers_spec.rb +303 -0
- data/spec/integration/erb_spec.rb +83 -0
- data/spec/integration/haml_spec.rb +59 -0
- data/spec/integration/rails_spec.rb +42 -0
- data/spec/integration/sinatra_spec.rb +42 -0
- data/spec/spec_helper.rb +54 -0
- data/spec/support/form_helper.rb +34 -0
- data/spec/support/list_helper.rb +14 -0
- data/spec/support/rails_app.rb +44 -0
- data/spec/support/sinatra_app.rb +26 -0
- data/spec/widget_spec.rb +146 -0
- data/tiny.gemspec +31 -0
- metadata +237 -0
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe 'markup helpers' do
|
5
|
+
include Tiny::Helpers
|
6
|
+
|
7
|
+
let(:output) do
|
8
|
+
Capybara::Node::Simple.new(@output)
|
9
|
+
end
|
10
|
+
|
11
|
+
def span &block
|
12
|
+
with_buffer do
|
13
|
+
tag(:span, &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def check_block &block
|
18
|
+
erb_block?(block).should be_true
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should determine block origin' do
|
22
|
+
Tilt['erb'].new { '<% check_block do %><% end %>' }.render(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should capture erb' do
|
26
|
+
Tilt['erb'].new { '<% mk = with_buffer("Tiny!") do |s| %>Hello <%= s %><% end %><%- mk.should == "Hello Tiny!" %>' }.render(self)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should emit tag' do
|
30
|
+
@output = Tilt['erb'].new { '<%= tag(:div) %>' }.render(self)
|
31
|
+
output.should have_css 'div', :count => 1
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should not buffer multiple tags' do
|
35
|
+
template = Tilt['erb'].new { '<%= yield %>' }
|
36
|
+
output = template.render(self) { tag(:span); tag(:a) }
|
37
|
+
output.should == '<a></a>'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should buffer multiple tags inside with_buffer block' do
|
41
|
+
template = Tilt['erb'].new { '<%= yield %>' }
|
42
|
+
output = template.render(self) { with_buffer { tag(:span); tag(:a) } }
|
43
|
+
output.should == "<span></span>\n<a></a>\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should concat erb block' do
|
47
|
+
template = Tilt['erb'].new(:outvar => '@_out_buf') { '<%= span do %>Hello<% end %>' }
|
48
|
+
template.render(self).should == "<span>\n Hello\n</span>\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'block passing' do
|
52
|
+
describe 'shallow' do
|
53
|
+
before do
|
54
|
+
@output = Tilt['erb'].new(:outvar => '@_out_buf') do
|
55
|
+
<<-ERB
|
56
|
+
<%= tag(:div) do %>
|
57
|
+
<%= tag(:a) do %>
|
58
|
+
Hello
|
59
|
+
<% end %>
|
60
|
+
<% end %>
|
61
|
+
ERB
|
62
|
+
end.render(self)
|
63
|
+
end
|
64
|
+
it { output.should have_css 'div', :count => 1 }
|
65
|
+
it { output.should have_css 'a', :count => 1 }
|
66
|
+
it { output.should have_css 'div > a', :text => 'Hello' }
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'nested' do
|
70
|
+
before do
|
71
|
+
@output = Renderer.new('erb_list.erb').render
|
72
|
+
end
|
73
|
+
it_should_behave_like 'it renders my list'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'with helpers' do
|
78
|
+
before do
|
79
|
+
@output = Renderer.new('erb_list_with_helpers.erb').render
|
80
|
+
end
|
81
|
+
it_should_behave_like 'it renders my list'
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe 'markup helpers' do
|
5
|
+
include Tiny::Helpers
|
6
|
+
|
7
|
+
let(:output) do
|
8
|
+
Capybara::Node::Simple.new(@output)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'tag' do
|
12
|
+
it 'should emit tag' do
|
13
|
+
@output = Tilt['haml'].new { '= tag(:div)' }.render(self)
|
14
|
+
output.should have_css 'div', :count => 1
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should emit haml block' do
|
18
|
+
@output = Tilt['haml'].new do
|
19
|
+
<<-HAML
|
20
|
+
= tag(:div) do
|
21
|
+
Hello
|
22
|
+
HAML
|
23
|
+
end.render(self)
|
24
|
+
output.should have_css 'div', :text => "Hello", :count => 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'passing blocks' do
|
29
|
+
describe 'shallow' do
|
30
|
+
before do
|
31
|
+
@output = Tilt['haml'].new do
|
32
|
+
<<-HAML
|
33
|
+
= tag(:div) do
|
34
|
+
= tag(:a) do
|
35
|
+
Hello
|
36
|
+
HAML
|
37
|
+
end.render(self)
|
38
|
+
end
|
39
|
+
it { output.should have_css 'div', :count => 1 }
|
40
|
+
it { output.should have_css 'a', :count => 1 }
|
41
|
+
it { output.should have_css 'div > a', :text => 'Hello' }
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'nested' do
|
45
|
+
before do
|
46
|
+
@output = Tilt.new("#{FIXTURES}/haml_list.haml").render(self)
|
47
|
+
end
|
48
|
+
|
49
|
+
it_should_behave_like 'it renders my list'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'with helpers' do
|
54
|
+
before do
|
55
|
+
@output = Renderer.new('haml_list_with_helpers.haml').render
|
56
|
+
end
|
57
|
+
it_should_behave_like 'it renders my list'
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require "#{SUPPORT}/rails_app"
|
3
|
+
|
4
|
+
describe 'Rails compatibility', :type => :request do
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
let(:output) do
|
8
|
+
Capybara::Node::Simple.new(page.body)
|
9
|
+
end
|
10
|
+
|
11
|
+
before do
|
12
|
+
Capybara.app = RailsTestApp::Application
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'using Tiny from erb template' do
|
16
|
+
before do
|
17
|
+
visit '/erb'
|
18
|
+
end
|
19
|
+
it_should_behave_like 'it renders my list'
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'using Tiny helpers from erb template' do
|
23
|
+
before do
|
24
|
+
visit '/erb_helpers'
|
25
|
+
end
|
26
|
+
it_should_behave_like 'it renders my list'
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'using Tiny from haml template' do
|
30
|
+
before do
|
31
|
+
visit '/haml'
|
32
|
+
end
|
33
|
+
it_should_behave_like 'it renders my list'
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'using Tiny helpers from haml template' do
|
37
|
+
before do
|
38
|
+
visit '/haml_helpers'
|
39
|
+
end
|
40
|
+
it_should_behave_like 'it renders my list'
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require "#{SUPPORT}/sinatra_app"
|
3
|
+
|
4
|
+
describe 'Sinatra compatibility', :type => :request do
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
let(:output) do
|
8
|
+
Capybara::Node::Simple.new(page.body)
|
9
|
+
end
|
10
|
+
|
11
|
+
before do
|
12
|
+
Capybara.app = SinatraTestApp
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'using Tiny from erb template' do
|
16
|
+
before do
|
17
|
+
visit '/erb'
|
18
|
+
end
|
19
|
+
it_should_behave_like 'it renders my list'
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'using Tiny helpers from erb template' do
|
23
|
+
before do
|
24
|
+
visit '/erb_helpers'
|
25
|
+
end
|
26
|
+
it_should_behave_like 'it renders my list'
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'using Tiny from haml template' do
|
30
|
+
before do
|
31
|
+
visit '/haml'
|
32
|
+
end
|
33
|
+
it_should_behave_like 'it renders my list'
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'using Tiny helpers from haml template' do
|
37
|
+
before do
|
38
|
+
visit '/haml_helpers'
|
39
|
+
end
|
40
|
+
it_should_behave_like 'it renders my list'
|
41
|
+
end
|
42
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'rspec'
|
4
|
+
require 'capybara/rspec'
|
5
|
+
# require 'erubis'
|
6
|
+
require 'rails'
|
7
|
+
require 'action_controller/railtie'
|
8
|
+
require 'haml'
|
9
|
+
require 'sinatra'
|
10
|
+
require 'tiny'
|
11
|
+
|
12
|
+
$:.unshift File.dirname(__FILE__)
|
13
|
+
require 'support/list_helper'
|
14
|
+
|
15
|
+
FIXTURES = "#{File.dirname __FILE__}/fixtures"
|
16
|
+
SUPPORT = "#{File.dirname __FILE__}/support"
|
17
|
+
|
18
|
+
shared_examples_for 'it renders my list' do
|
19
|
+
it { output.should have_css 'ul', :count => 1 }
|
20
|
+
it { output.should have_css 'li', :count => 3 }
|
21
|
+
it { output.should have_css 'a', :count => 3 }
|
22
|
+
it { output.should have_css 'span', :count => 3 }
|
23
|
+
it { output.should have_css 'ul > li' }
|
24
|
+
it { output.should have_css 'ul > li > a' }
|
25
|
+
it { output.should have_css 'ul > li > a', :text => 'A' }
|
26
|
+
it { output.should have_css 'ul > li > a > span', :text => '1' }
|
27
|
+
it { output.should have_css 'ul > li > a', :text => 'B' }
|
28
|
+
it { output.should have_css 'ul > li > a > span', :text => '2' }
|
29
|
+
it { output.should have_css 'ul > li > a', :text => 'C' }
|
30
|
+
it { output.should have_css 'ul > li > a > span', :text => '3' }
|
31
|
+
end
|
32
|
+
|
33
|
+
shared_examples_for 'it renders my form' do
|
34
|
+
it { output.should have_css 'form', :count => 1 }
|
35
|
+
it { output.should have_css 'form[action="/login"]', :count => 1 }
|
36
|
+
it { output.should have_css 'form > fieldset', :count => 1 }
|
37
|
+
it { output.should have_css 'form > fieldset > label', :count => 1}
|
38
|
+
it { output.should have_css 'form > fieldset > label[for=email]', :text => 'Email', :count => 1}
|
39
|
+
it { output.should have_css 'form > fieldset > input', :count => 1}
|
40
|
+
it { output.should have_css 'form > fieldset > input#email[type=text][value="email@example.com"]', :count => 1 }
|
41
|
+
end
|
42
|
+
|
43
|
+
class Renderer
|
44
|
+
include Tiny::Helpers
|
45
|
+
include ListHelper
|
46
|
+
|
47
|
+
def initialize template
|
48
|
+
@template = template
|
49
|
+
end
|
50
|
+
|
51
|
+
def render
|
52
|
+
Tilt.new("#{FIXTURES}/#{@template}", :outvar => '@output').render(self)
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module FormHelper
|
2
|
+
class MyForm < Tiny::Widget
|
3
|
+
def initialize(action)
|
4
|
+
@action = action
|
5
|
+
end
|
6
|
+
|
7
|
+
def markup
|
8
|
+
form(:action => @action) do
|
9
|
+
fieldset do
|
10
|
+
yield(self)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def text_input(name, value)
|
16
|
+
TextInput.new(name, value).to_html
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class TextInput < Tiny::Widget
|
21
|
+
def initialize(name, value)
|
22
|
+
@name, @value = name, value
|
23
|
+
end
|
24
|
+
|
25
|
+
def markup
|
26
|
+
label(@name.capitalize, :for => @name)
|
27
|
+
input(:type => 'text', :id => @name, :name => @name, :value => @value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def my_form(action, &block)
|
32
|
+
MyForm.new(action).to_html(&block)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
Rails.logger = Logger.new(STDOUT)
|
2
|
+
Rails.logger.level = 3
|
3
|
+
|
4
|
+
ActionController::Base.view_paths = FIXTURES
|
5
|
+
|
6
|
+
module RailsTestApp
|
7
|
+
class Application < Rails::Application
|
8
|
+
config.secret_token = '572c86f5ede338bd8aba8dae0fd3a326aabababc98d1e6ce34b9f5'
|
9
|
+
|
10
|
+
routes.draw do
|
11
|
+
get '/erb' => 'rails_test_app/test#erb'
|
12
|
+
get '/erb_helpers' => 'rails_test_app/test#erb_helpers'
|
13
|
+
get '/haml' => 'rails_test_app/test#haml'
|
14
|
+
get '/haml_helpers' => 'rails_test_app/test#haml_helpers'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class TestController < ActionController::Base
|
19
|
+
helper do
|
20
|
+
include ActionView::Helpers::TextHelper
|
21
|
+
include ActionView::Helpers::UrlHelper
|
22
|
+
include ListHelper
|
23
|
+
end
|
24
|
+
|
25
|
+
def erb
|
26
|
+
render :template => "erb_list"
|
27
|
+
end
|
28
|
+
|
29
|
+
def erb_helpers
|
30
|
+
render :template => "erb_list_with_helpers"
|
31
|
+
end
|
32
|
+
|
33
|
+
def haml
|
34
|
+
render :template => "haml_list"
|
35
|
+
end
|
36
|
+
|
37
|
+
def haml_helpers
|
38
|
+
render :template => "haml_list_with_helpers"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Rails app boot
|
44
|
+
require 'haml/template'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
|
3
|
+
class SinatraTestApp < Sinatra::Base
|
4
|
+
enable :sessions
|
5
|
+
set :environment, :test
|
6
|
+
set :views, "#{File.dirname __FILE__}/../fixtures"
|
7
|
+
|
8
|
+
helpers Tiny::Helpers
|
9
|
+
helpers ListHelper
|
10
|
+
|
11
|
+
get '/erb' do
|
12
|
+
erb :erb_list
|
13
|
+
end
|
14
|
+
|
15
|
+
get '/haml' do
|
16
|
+
haml :haml_list
|
17
|
+
end
|
18
|
+
|
19
|
+
get '/erb_helpers' do
|
20
|
+
erb :erb_list_with_helpers
|
21
|
+
end
|
22
|
+
|
23
|
+
get '/haml_helpers' do
|
24
|
+
haml :haml_list_with_helpers
|
25
|
+
end
|
26
|
+
end
|
data/spec/widget_spec.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'support/form_helper'
|
4
|
+
|
5
|
+
describe Tiny::Widget do
|
6
|
+
include Tiny::Helpers
|
7
|
+
|
8
|
+
let(:output) do
|
9
|
+
Capybara::Node::Simple.new(@output)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "simple widget" do
|
13
|
+
it 'should output content' do
|
14
|
+
output = Class.new(Tiny::Widget) do
|
15
|
+
def markup
|
16
|
+
append! '<div></div>'
|
17
|
+
end
|
18
|
+
end.new.to_html
|
19
|
+
output.should == "<div></div>\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should output content with block' do
|
23
|
+
output = Class.new(Tiny::Widget) do
|
24
|
+
def markup
|
25
|
+
append! "<div>"
|
26
|
+
yield
|
27
|
+
append! "</div>"
|
28
|
+
end
|
29
|
+
end.new.to_html { text 'Hello' }
|
30
|
+
output.should == "<div>\nHello\n</div>\n"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "page widget" do
|
35
|
+
before do
|
36
|
+
@output = Class.new(Tiny::Widget) do
|
37
|
+
def markup
|
38
|
+
head { title "Tiny Page!" }
|
39
|
+
body { h1 "Hello Tiny!" }
|
40
|
+
end
|
41
|
+
end.new.to_html
|
42
|
+
end
|
43
|
+
|
44
|
+
it { output.should have_css 'head', :count => 1 }
|
45
|
+
it { output.should have_css 'head > title', :text => "Tiny Page!", :count => 1 }
|
46
|
+
it { output.should have_css 'body', :count => 1 }
|
47
|
+
it { output.should have_css 'body > h1', :text => "Hello Tiny!", :count => 1 }
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'content from different methods' do
|
51
|
+
before do
|
52
|
+
@output = Class.new(Tiny::Widget) do
|
53
|
+
def notices
|
54
|
+
div :id => :notices do
|
55
|
+
h1 'Notices'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def main
|
60
|
+
div :id => :content do
|
61
|
+
h1 "Content"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def markup
|
66
|
+
notices
|
67
|
+
main
|
68
|
+
end
|
69
|
+
end.new.to_html
|
70
|
+
end
|
71
|
+
|
72
|
+
it { output.should have_css 'div#notices', :count => 1 }
|
73
|
+
it { output.should have_css 'div#notices > h1', :text => "Notices", :count => 1 }
|
74
|
+
it { output.should have_css 'div#content', :count => 1 }
|
75
|
+
it { output.should have_css 'div#content > h1', :text => "Content", :count => 1 }
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'rendering a tag from outside' do
|
79
|
+
before do
|
80
|
+
@title = "Content" # no need to smuggle instance variables
|
81
|
+
@output = Class.new(Tiny::Widget) do
|
82
|
+
def markup
|
83
|
+
div :id => :content do
|
84
|
+
yield
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end.new.to_html { tag :h1, @title }
|
88
|
+
end
|
89
|
+
|
90
|
+
it { output.should have_css 'div#content', :count => 1 }
|
91
|
+
it { output.should have_css 'div#content > h1', :text => "Content", :count => 1 }
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'rendering a block from outside with concatenated tags' do
|
95
|
+
before do
|
96
|
+
@output = Class.new(Tiny::Widget) do
|
97
|
+
def markup &block
|
98
|
+
div(:id => :content, &block)
|
99
|
+
end
|
100
|
+
end.new.to_html { tag(:h1, "Title"); tag(:p, "Content") }
|
101
|
+
end
|
102
|
+
|
103
|
+
it { output.should have_css 'div#content', :count => 1 }
|
104
|
+
it { output.should have_css 'div#content > h1', :text => "Title", :count => 1 }
|
105
|
+
it { output.should have_css 'div#content > p', :text => "Content", :count => 1 }
|
106
|
+
end
|
107
|
+
|
108
|
+
describe 'rendering an erb block' do
|
109
|
+
before do
|
110
|
+
widget = Class.new(Tiny::Widget) do
|
111
|
+
def markup &block
|
112
|
+
div(:id => :content, &block)
|
113
|
+
end
|
114
|
+
end.new
|
115
|
+
@output = Tilt['erb'].new { '<%= widget.to_html do %><h1>Title</h1><p>Content</p><% end %>' }.render(self, :widget => widget)
|
116
|
+
end
|
117
|
+
|
118
|
+
it { output.should have_css 'div#content', :count => 1 }
|
119
|
+
it { output.should have_css 'div#content > h1', :text => "Title", :count => 1 }
|
120
|
+
it { output.should have_css 'div#content > p', :text => "Content", :count => 1 }
|
121
|
+
end
|
122
|
+
|
123
|
+
describe 'widget with no content overriden' do
|
124
|
+
it 'should raise not implemented' do
|
125
|
+
lambda do
|
126
|
+
Class.new(Tiny::Widget).new.to_html
|
127
|
+
end.should raise_error(NotImplementedError)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'view helpers using Widget' do
|
132
|
+
include FormHelper
|
133
|
+
before do
|
134
|
+
@output = my_form('/login') { |form| append! form.text_input 'email', 'email@example.com' }
|
135
|
+
end
|
136
|
+
it_should_behave_like 'it renders my form'
|
137
|
+
end
|
138
|
+
|
139
|
+
describe 'ERB view helpers using Widget' do
|
140
|
+
include FormHelper
|
141
|
+
before do
|
142
|
+
@output = Tilt['erb'].new { '<%= my_form("/login") do |form| %><%= form.text_input "email", "email@example.com" %><% end %>' }.render(self)
|
143
|
+
end
|
144
|
+
it_should_behave_like 'it renders my form'
|
145
|
+
end
|
146
|
+
end
|