rack-mason 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/CHANGELOG +24 -0
- data/Gemfile +16 -0
- data/LICENSE +21 -0
- data/README.rdoc +54 -0
- data/Rakefile +23 -0
- data/examples/middlewares/initial.rb +27 -0
- data/examples/middlewares/intro.rb +16 -0
- data/examples/middlewares/l337.rb +21 -0
- data/examples/middlewares/stylizer.rb +15 -0
- data/examples/rackapp/app.rb +105 -0
- data/examples/rackapp/config.ru +16 -0
- data/examples/railsapp/README +243 -0
- data/examples/railsapp/Rakefile +10 -0
- data/examples/railsapp/app/controllers/application_controller.rb +10 -0
- data/examples/railsapp/app/controllers/tommy_boy_controller.rb +9 -0
- data/examples/railsapp/app/helpers/application_helper.rb +3 -0
- data/examples/railsapp/app/helpers/tommy_boy_helper.rb +2 -0
- data/examples/railsapp/app/views/layouts/application.html.erb +13 -0
- data/examples/railsapp/app/views/tommy_boy/index.html.erb +44 -0
- data/examples/railsapp/app/views/tommy_boy/more.html.erb +12 -0
- data/examples/railsapp/config/boot.rb +110 -0
- data/examples/railsapp/config/database.yml +22 -0
- data/examples/railsapp/config/environment.rb +50 -0
- data/examples/railsapp/config/environments/development.rb +17 -0
- data/examples/railsapp/config/environments/production.rb +28 -0
- data/examples/railsapp/config/environments/test.rb +28 -0
- data/examples/railsapp/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/railsapp/config/initializers/inflections.rb +10 -0
- data/examples/railsapp/config/initializers/mime_types.rb +5 -0
- data/examples/railsapp/config/initializers/new_rails_defaults.rb +21 -0
- data/examples/railsapp/config/initializers/session_store.rb +15 -0
- data/examples/railsapp/config/locales/en.yml +5 -0
- data/examples/railsapp/config/routes.rb +4 -0
- data/examples/railsapp/db/development.sqlite3 +0 -0
- data/examples/railsapp/db/seeds.rb +7 -0
- data/examples/railsapp/doc/README_FOR_APP +2 -0
- data/examples/railsapp/public/404.html +30 -0
- data/examples/railsapp/public/422.html +30 -0
- data/examples/railsapp/public/500.html +30 -0
- data/examples/railsapp/public/favicon.ico +0 -0
- data/examples/railsapp/public/images/rails.png +0 -0
- data/examples/railsapp/public/javascripts/application.js +2 -0
- data/examples/railsapp/public/javascripts/controls.js +963 -0
- data/examples/railsapp/public/javascripts/dragdrop.js +973 -0
- data/examples/railsapp/public/javascripts/effects.js +1128 -0
- data/examples/railsapp/public/javascripts/prototype.js +4320 -0
- data/examples/railsapp/public/robots.txt +5 -0
- data/examples/railsapp/script/about +4 -0
- data/examples/railsapp/script/console +3 -0
- data/examples/railsapp/script/dbconsole +3 -0
- data/examples/railsapp/script/destroy +3 -0
- data/examples/railsapp/script/generate +3 -0
- data/examples/railsapp/script/performance/benchmarker +3 -0
- data/examples/railsapp/script/performance/profiler +3 -0
- data/examples/railsapp/script/plugin +3 -0
- data/examples/railsapp/script/runner +3 -0
- data/examples/railsapp/script/server +3 -0
- data/examples/railsapp/test/functional/tommy_boy_controller_test.rb +8 -0
- data/examples/railsapp/test/performance/browsing_test.rb +9 -0
- data/examples/railsapp/test/test_helper.rb +38 -0
- data/examples/railsapp/test/unit/helpers/tommy_boy_helper_test.rb +4 -0
- data/examples/sinatraapp/app.rb +107 -0
- data/gem.yml +17 -0
- data/lib/mason_helper.rb +76 -0
- data/lib/mason_test_helper.rb +99 -0
- data/lib/rack-mason.rb +70 -0
- data/test/rack-mason_test.rb +21 -0
- data/test/test_helper.rb +13 -0
- data/vex/gem.rake +36 -0
- data/vex/gem.rb +95 -0
- metadata +197 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
ENV["RAILS_ENV"] = "test"
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
|
3
|
+
require 'test_help'
|
4
|
+
|
5
|
+
class ActiveSupport::TestCase
|
6
|
+
# Transactional fixtures accelerate your tests by wrapping each test method
|
7
|
+
# in a transaction that's rolled back on completion. This ensures that the
|
8
|
+
# test database remains unchanged so your fixtures don't have to be reloaded
|
9
|
+
# between every test method. Fewer database queries means faster tests.
|
10
|
+
#
|
11
|
+
# Read Mike Clark's excellent walkthrough at
|
12
|
+
# http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
|
13
|
+
#
|
14
|
+
# Every Active Record database supports transactions except MyISAM tables
|
15
|
+
# in MySQL. Turn off transactional fixtures in this case; however, if you
|
16
|
+
# don't care one way or the other, switching from MyISAM to InnoDB tables
|
17
|
+
# is recommended.
|
18
|
+
#
|
19
|
+
# The only drawback to using transactional fixtures is when you actually
|
20
|
+
# need to test transactions. Since your test is bracketed by a transaction,
|
21
|
+
# any transactions started in your code will be automatically rolled back.
|
22
|
+
self.use_transactional_fixtures = true
|
23
|
+
|
24
|
+
# Instantiated fixtures are slow, but give you @david where otherwise you
|
25
|
+
# would need people(:david). If you don't want to migrate your existing
|
26
|
+
# test cases which use the @david style and don't mind the speed hit (each
|
27
|
+
# instantiated fixtures translates to a database query per test method),
|
28
|
+
# then set this back to true.
|
29
|
+
self.use_instantiated_fixtures = false
|
30
|
+
|
31
|
+
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
|
32
|
+
#
|
33
|
+
# Note: You'll currently still have to declare fixtures explicitly in integration tests
|
34
|
+
# -- they do not yet inherit this setting
|
35
|
+
fixtures :all
|
36
|
+
|
37
|
+
# Add more helper methods to be used by all tests here...
|
38
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sinatra'
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'middlewares', 'initial')
|
4
|
+
require File.join(File.dirname(__FILE__), '..', 'middlewares', 'intro')
|
5
|
+
require File.join(File.dirname(__FILE__), '..', 'middlewares', 'l337')
|
6
|
+
require File.join(File.dirname(__FILE__), '..', 'middlewares', 'stylizer')
|
7
|
+
|
8
|
+
# Note that these middlewares will seem to be applied in backwards order.
|
9
|
+
# In other words, Rack::Stylizer parses the resulting HTML first, then
|
10
|
+
# passes it to Rack::Initial, then to Rack::L337, and finally to Rack::Intro.
|
11
|
+
|
12
|
+
1.times do
|
13
|
+
use Rack::Intro
|
14
|
+
use Rack::L337
|
15
|
+
use Rack::Initial
|
16
|
+
use Rack::Stylizer
|
17
|
+
end
|
18
|
+
|
19
|
+
get '/' do
|
20
|
+
%Q{
|
21
|
+
<!DOCTYPE html
|
22
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
23
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
24
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
25
|
+
<head>
|
26
|
+
<title>The Greatest Movie of All Time</title>
|
27
|
+
</head>
|
28
|
+
<body>
|
29
|
+
<div id="container">
|
30
|
+
<p>
|
31
|
+
What my associate is trying to say is that our new brake pads are really cool.
|
32
|
+
You're not even gonna believe it.
|
33
|
+
</p>
|
34
|
+
<p>
|
35
|
+
Like, um, let's say you're driving along
|
36
|
+
the road, with your family.<br />
|
37
|
+
And you're driving along...la de da...woo...<br />
|
38
|
+
And then all of a sudden
|
39
|
+
there's a truck tire
|
40
|
+
in the middle of the road
|
41
|
+
and you hit the brakes.<br />
|
42
|
+
Screeeee!
|
43
|
+
</p>
|
44
|
+
<p>
|
45
|
+
Woah, that was close.
|
46
|
+
</p>
|
47
|
+
<p>
|
48
|
+
Now let's see what happens when you're
|
49
|
+
driving with "the other guy's brake pads".
|
50
|
+
</p>
|
51
|
+
<p>
|
52
|
+
You're driving along,<br />
|
53
|
+
you're driving along,<br />
|
54
|
+
and all of a sudden your kids are
|
55
|
+
yelling from the back seat:<br />
|
56
|
+
"I gotta go to the bathroom, daddy!"<br />
|
57
|
+
"Not now, dammit!"<br />
|
58
|
+
"Truck tire! I can't stop! Aaaaa! Help!"<br />
|
59
|
+
"There's a cliff! Aaaaa!"<br />
|
60
|
+
And your family screaming:<br />
|
61
|
+
"Oh my God, we're burning alive!"<br />
|
62
|
+
"No! I can't feel my legs!"<br />
|
63
|
+
Here comes the meat-wagon! Woo woo woo!<br />
|
64
|
+
And the medic gets out and says:<br />
|
65
|
+
"Oh! My! God!"<br />
|
66
|
+
New guy's in the corner puking his guts out:<br />
|
67
|
+
Blllleeeeeeeaaaaaaaaaaah!<br />
|
68
|
+
Blllleeeeeeeaaaaaaaaaaah!<br />
|
69
|
+
</p>
|
70
|
+
<p>
|
71
|
+
All because you wanna save a coupla extra pennies.
|
72
|
+
</p>
|
73
|
+
<a href="/more">« inflict me with more »</a>
|
74
|
+
</div>
|
75
|
+
</body>
|
76
|
+
</html>
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
get '/more' do
|
81
|
+
%Q{
|
82
|
+
<!DOCTYPE html
|
83
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
84
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
85
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
86
|
+
<head>
|
87
|
+
<title>More of the Greatest Movie of All Time</title>
|
88
|
+
</head>
|
89
|
+
<body>
|
90
|
+
<div id="container">
|
91
|
+
<p>
|
92
|
+
D+? Oh my God! I passed! I passed! Oh, man i got a D+! I'm gonna graduate!
|
93
|
+
I'm gonna graduate! D+!
|
94
|
+
</p>
|
95
|
+
<p>
|
96
|
+
Hey guys, do i look different now that i'm a college grad?
|
97
|
+
</p>
|
98
|
+
<p>
|
99
|
+
Apparently they give a lot fewer D+'s than D-'s.
|
100
|
+
It's not a grade they like to give out, i'll tell ya that right now.
|
101
|
+
</p>
|
102
|
+
<a href="/">« take me back »</a>
|
103
|
+
</div>
|
104
|
+
</body>
|
105
|
+
</html>
|
106
|
+
}
|
107
|
+
end
|
data/gem.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
name: "rack-mason"
|
2
|
+
version: "0.1.2"
|
3
|
+
summary: "Helps you write Rack middleware using Nokogiri."
|
4
|
+
description:
|
5
|
+
If you are creating Rack middleware that changes the HTML response, use
|
6
|
+
Rack::Mason to get a head start. Rack::Mason takes care of the
|
7
|
+
boilerplate Rack glue so that you can focus on simply changing the HTML.
|
8
|
+
|
9
|
+
Note: this is a fork from https://github.com/techiferous/rack-mason (c) techiferous@gmail.com
|
10
|
+
homepage: http://github.com/radiospiel/rack-mason
|
11
|
+
author: radiospiel
|
12
|
+
email: radiospiel@open-lab.org
|
13
|
+
dependencies:
|
14
|
+
- nokogiri
|
15
|
+
- rack
|
16
|
+
- diffy
|
17
|
+
- colored
|
data/lib/mason_helper.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
class NokogiriString
|
2
|
+
attr :nokogiri
|
3
|
+
|
4
|
+
def initialize(nokogiri)
|
5
|
+
@nokogiri = nokogiri
|
6
|
+
end
|
7
|
+
|
8
|
+
# A NokogiriString is not really a String, but is good enought
|
9
|
+
# in the Rack context to act like one.
|
10
|
+
def kind_of?(what)
|
11
|
+
return true if what == String
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_str
|
16
|
+
@to_str ||= @nokogiri.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def bytesize
|
20
|
+
to_str.bytesize
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
to_str
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module Rack
|
29
|
+
|
30
|
+
# MasonHelper was created to separate Mason's implementation from Mason's
|
31
|
+
# interface.
|
32
|
+
#
|
33
|
+
# This class basically contains all of the Rack code that you'd have to write every
|
34
|
+
# time you wanted to write a new middleware that modifies the HTML response.
|
35
|
+
#
|
36
|
+
module MasonHelper #:nodoc:
|
37
|
+
|
38
|
+
# Rack::Mason provides a call method so that your middleware doesn't have to.
|
39
|
+
def call(env)
|
40
|
+
status, @headers, @body = @app.call(env)
|
41
|
+
if status == 200 && html?
|
42
|
+
@request = Rack::Request.new(env)
|
43
|
+
body_string = @body.length == 1 ? @body[0] : @body.join("")
|
44
|
+
|
45
|
+
doc = body_string.respond_to?(:nokogiri) ? body_string.nokogiri : Nokogiri::HTML(body_string)
|
46
|
+
|
47
|
+
if doc && update_body(doc) != false
|
48
|
+
update_response_body(NokogiriString.new(doc))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
[status, @headers, @body]
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def html?
|
58
|
+
@headers["Content-Type"].to_s.include?("text/html")
|
59
|
+
end
|
60
|
+
|
61
|
+
def update_response_body(body)
|
62
|
+
# If we're dealing with a Rails response, we don't want to throw the
|
63
|
+
# response object away, we just want to update the response string.
|
64
|
+
if @body.class.name == "ActionController::Response"
|
65
|
+
@body.body = body
|
66
|
+
else
|
67
|
+
@body = [body]
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# The content lenght might have changed... but there is Rack::ContentLength to add
|
72
|
+
# it later on again.
|
73
|
+
@headers.delete 'Content-Length'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'rack/mock'
|
2
|
+
require 'diffy'
|
3
|
+
require 'colored'
|
4
|
+
|
5
|
+
# Mix this module into Test::Unit::TestCase to have access to these
|
6
|
+
# test helpers when using Test::Unit.
|
7
|
+
#
|
8
|
+
# Here's an example of how you can use these helper methods:
|
9
|
+
#
|
10
|
+
# def test_basic_document
|
11
|
+
# before_html = %Q{
|
12
|
+
# <!DOCTYPE html
|
13
|
+
# PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
14
|
+
# "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
15
|
+
# <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
16
|
+
# <head>
|
17
|
+
# <title>Testing Rack::SexChange</title>
|
18
|
+
# </head>
|
19
|
+
# <body>
|
20
|
+
# Hi, Mom!
|
21
|
+
# </body>
|
22
|
+
# </html>
|
23
|
+
# }
|
24
|
+
# expected_html = %Q{
|
25
|
+
# <!DOCTYPE html
|
26
|
+
# PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
27
|
+
# "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
28
|
+
# <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
29
|
+
# <head>
|
30
|
+
# <title>Testing Rack::SexChange</title>
|
31
|
+
# </head>
|
32
|
+
# <body>
|
33
|
+
# Hi, Dad!
|
34
|
+
# </body>
|
35
|
+
# </html>
|
36
|
+
# }
|
37
|
+
# after_html = process_html(before_html, Rack::SexChange)
|
38
|
+
# assert_html_equal expected_html, after_html
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# And here's an example of how you'd mix these helper methods into
|
42
|
+
# Test::Unit::TestCase:
|
43
|
+
#
|
44
|
+
# require 'test/unit'
|
45
|
+
# require 'rubygems'
|
46
|
+
# require 'plastic_test_helper'
|
47
|
+
#
|
48
|
+
# module Test
|
49
|
+
# module Unit
|
50
|
+
# class TestCase
|
51
|
+
#
|
52
|
+
# include MasonTestHelper
|
53
|
+
#
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
module MasonTestHelper
|
59
|
+
|
60
|
+
# This takes care of the "plumbing" involved in testing your middleware.
|
61
|
+
# All you have to provide is an input HTML string, the class of
|
62
|
+
# your middleware (not the name of your class or an object, but
|
63
|
+
# the class itself), and finally some optional options to use when
|
64
|
+
# instantiating your middleware class.
|
65
|
+
#
|
66
|
+
# This method will run the input HTML string through the middleware
|
67
|
+
# and return the resulting HTML string (the body of the middleware's response).
|
68
|
+
#
|
69
|
+
# Examples:
|
70
|
+
# resulting_html = process_html(input_html, Rack::Linkify)
|
71
|
+
# resulting_html = process_html(input_html, Rack::Linkify, :twitter => true)
|
72
|
+
#
|
73
|
+
def process_html(html, middleware_class, options={})
|
74
|
+
app = lambda { |env| [200, {'Content-Type' => 'text/html'}, [html]] }
|
75
|
+
app2 = middleware_class.new(app, options)
|
76
|
+
Rack::MockRequest.new(app2).get('/', :lint => true).body
|
77
|
+
end
|
78
|
+
|
79
|
+
# this convenience method makes it easy to test changes to HTML strings
|
80
|
+
#
|
81
|
+
def assert_html_equal(expected_html_string, actual_html_string)
|
82
|
+
# Nokogiri does not preserve the same whitespace between tags when
|
83
|
+
# it processes HTML. This means we can't do a simple string comparison.
|
84
|
+
# However, if we run both the expected HTML string and the actual HTML
|
85
|
+
# string through Nokogiri, then the whitespace will be changed in
|
86
|
+
# the same way and we can do a simple string comparison.
|
87
|
+
expected = Nokogiri::HTML(expected_html_string).to_html
|
88
|
+
actual = Nokogiri::HTML(actual_html_string).to_html
|
89
|
+
preamble = "\n"
|
90
|
+
preamble = "*****************************************************\n"
|
91
|
+
preamble << "* The actual HTML does not match the expected HTML. *\n"
|
92
|
+
preamble << "* The differences are highlighted below. *\n"
|
93
|
+
preamble << "*****************************************************\n"
|
94
|
+
message = preamble.magenta
|
95
|
+
message << Diffy::Diff.new(expected, actual).to_s(:color)
|
96
|
+
assert_block(message) { expected == actual }
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
data/lib/rack-mason.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require File.join(File.dirname(__FILE__), 'mason_helper')
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
|
6
|
+
# If you are creating Rack middleware that changes the HTML response, inherit
|
7
|
+
# from Rack::Mason to get a head start. Rack::Mason takes care of the
|
8
|
+
# boilerplate Rack glue so that you can focus on simply changing the HTML.
|
9
|
+
#
|
10
|
+
# There are two ways you can change the HTML: as a Nokogiri document or as
|
11
|
+
# a string. Simply define one of the following methods:
|
12
|
+
#
|
13
|
+
# def update_body(doc)
|
14
|
+
# ... insert code that changes the doc ...
|
15
|
+
# doc
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# Rack::Mason also provides some convenience methods for interacting with
|
19
|
+
# Rack and Nokogiri.
|
20
|
+
#
|
21
|
+
class Mason
|
22
|
+
include MasonHelper
|
23
|
+
|
24
|
+
# Rack::Mason provides an initialize method so that your middleware
|
25
|
+
# doesn't have to.
|
26
|
+
#
|
27
|
+
def initialize(app, options = {}) #:nodoc:
|
28
|
+
@app = app
|
29
|
+
@options = options.freeze
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# returns the current request as a Rack::Request object
|
35
|
+
#
|
36
|
+
def request #:doc:
|
37
|
+
@request
|
38
|
+
end
|
39
|
+
|
40
|
+
# returns the hash of options that were given to your middleware
|
41
|
+
#
|
42
|
+
def options #:doc:
|
43
|
+
@options
|
44
|
+
end
|
45
|
+
|
46
|
+
# a convenience method for adding a new HTML element as the first child
|
47
|
+
# of another HTML element
|
48
|
+
#
|
49
|
+
def add_first_child(parent, new_child) #:doc:
|
50
|
+
parent.children.first.add_previous_sibling(new_child)
|
51
|
+
end
|
52
|
+
|
53
|
+
# a convenience method for quickly creating a new HTML element
|
54
|
+
#
|
55
|
+
def create_node(doc, node_name, content=nil) #:doc:
|
56
|
+
node = Nokogiri::XML::Node.new(node_name, doc)
|
57
|
+
node.content = content if content
|
58
|
+
node
|
59
|
+
end
|
60
|
+
|
61
|
+
# Nokogiri's node.content=(text) method automatically HTML escapes the given text.
|
62
|
+
# This can cause problems. This method updates the text of an HTML element
|
63
|
+
# without escaping the text.
|
64
|
+
#
|
65
|
+
def update_text(node, new_text) #:doc:
|
66
|
+
node.send(:native_content=, new_text)
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|