rack-mason 0.1.2
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.
- 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
|