rack-mason 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/.gitignore +4 -0
  2. data/CHANGELOG +24 -0
  3. data/Gemfile +16 -0
  4. data/LICENSE +21 -0
  5. data/README.rdoc +54 -0
  6. data/Rakefile +23 -0
  7. data/examples/middlewares/initial.rb +27 -0
  8. data/examples/middlewares/intro.rb +16 -0
  9. data/examples/middlewares/l337.rb +21 -0
  10. data/examples/middlewares/stylizer.rb +15 -0
  11. data/examples/rackapp/app.rb +105 -0
  12. data/examples/rackapp/config.ru +16 -0
  13. data/examples/railsapp/README +243 -0
  14. data/examples/railsapp/Rakefile +10 -0
  15. data/examples/railsapp/app/controllers/application_controller.rb +10 -0
  16. data/examples/railsapp/app/controllers/tommy_boy_controller.rb +9 -0
  17. data/examples/railsapp/app/helpers/application_helper.rb +3 -0
  18. data/examples/railsapp/app/helpers/tommy_boy_helper.rb +2 -0
  19. data/examples/railsapp/app/views/layouts/application.html.erb +13 -0
  20. data/examples/railsapp/app/views/tommy_boy/index.html.erb +44 -0
  21. data/examples/railsapp/app/views/tommy_boy/more.html.erb +12 -0
  22. data/examples/railsapp/config/boot.rb +110 -0
  23. data/examples/railsapp/config/database.yml +22 -0
  24. data/examples/railsapp/config/environment.rb +50 -0
  25. data/examples/railsapp/config/environments/development.rb +17 -0
  26. data/examples/railsapp/config/environments/production.rb +28 -0
  27. data/examples/railsapp/config/environments/test.rb +28 -0
  28. data/examples/railsapp/config/initializers/backtrace_silencers.rb +7 -0
  29. data/examples/railsapp/config/initializers/inflections.rb +10 -0
  30. data/examples/railsapp/config/initializers/mime_types.rb +5 -0
  31. data/examples/railsapp/config/initializers/new_rails_defaults.rb +21 -0
  32. data/examples/railsapp/config/initializers/session_store.rb +15 -0
  33. data/examples/railsapp/config/locales/en.yml +5 -0
  34. data/examples/railsapp/config/routes.rb +4 -0
  35. data/examples/railsapp/db/development.sqlite3 +0 -0
  36. data/examples/railsapp/db/seeds.rb +7 -0
  37. data/examples/railsapp/doc/README_FOR_APP +2 -0
  38. data/examples/railsapp/public/404.html +30 -0
  39. data/examples/railsapp/public/422.html +30 -0
  40. data/examples/railsapp/public/500.html +30 -0
  41. data/examples/railsapp/public/favicon.ico +0 -0
  42. data/examples/railsapp/public/images/rails.png +0 -0
  43. data/examples/railsapp/public/javascripts/application.js +2 -0
  44. data/examples/railsapp/public/javascripts/controls.js +963 -0
  45. data/examples/railsapp/public/javascripts/dragdrop.js +973 -0
  46. data/examples/railsapp/public/javascripts/effects.js +1128 -0
  47. data/examples/railsapp/public/javascripts/prototype.js +4320 -0
  48. data/examples/railsapp/public/robots.txt +5 -0
  49. data/examples/railsapp/script/about +4 -0
  50. data/examples/railsapp/script/console +3 -0
  51. data/examples/railsapp/script/dbconsole +3 -0
  52. data/examples/railsapp/script/destroy +3 -0
  53. data/examples/railsapp/script/generate +3 -0
  54. data/examples/railsapp/script/performance/benchmarker +3 -0
  55. data/examples/railsapp/script/performance/profiler +3 -0
  56. data/examples/railsapp/script/plugin +3 -0
  57. data/examples/railsapp/script/runner +3 -0
  58. data/examples/railsapp/script/server +3 -0
  59. data/examples/railsapp/test/functional/tommy_boy_controller_test.rb +8 -0
  60. data/examples/railsapp/test/performance/browsing_test.rb +9 -0
  61. data/examples/railsapp/test/test_helper.rb +38 -0
  62. data/examples/railsapp/test/unit/helpers/tommy_boy_helper_test.rb +4 -0
  63. data/examples/sinatraapp/app.rb +107 -0
  64. data/gem.yml +17 -0
  65. data/lib/mason_helper.rb +76 -0
  66. data/lib/mason_test_helper.rb +99 -0
  67. data/lib/rack-mason.rb +70 -0
  68. data/test/rack-mason_test.rb +21 -0
  69. data/test/test_helper.rb +13 -0
  70. data/vex/gem.rake +36 -0
  71. data/vex/gem.rb +95 -0
  72. metadata +197 -0
@@ -0,0 +1,5 @@
1
+ # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
2
+ #
3
+ # To ban all spiders from the entire site uncomment the next two lines:
4
+ # User-Agent: *
5
+ # Disallow: /
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ $LOAD_PATH.unshift "#{RAILTIES_PATH}/builtin/rails_info"
4
+ require 'commands/about'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/console'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/dbconsole'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/destroy'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/generate'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../../config/boot', __FILE__)
3
+ require 'commands/performance/benchmarker'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../../config/boot', __FILE__)
3
+ require 'commands/performance/profiler'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/plugin'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/runner'
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../config/boot', __FILE__)
3
+ require 'commands/server'
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ class TommyBoyControllerTest < ActionController::TestCase
4
+ # Replace this with your real tests.
5
+ test "the truth" do
6
+ assert true
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+ require 'performance_test_help'
3
+
4
+ # Profiling results for each test method are written to tmp/performance.
5
+ class BrowsingTest < ActionController::PerformanceTest
6
+ def test_homepage
7
+ get '/'
8
+ end
9
+ end
@@ -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,4 @@
1
+ require 'test_helper'
2
+
3
+ class TommyBoyHelperTest < ActionView::TestCase
4
+ 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">&laquo; inflict me with more &raquo;</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="/">&laquo; take me back &raquo;</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
@@ -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