rack-plastic 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/CHANGELOG +2 -0
  2. data/LICENSE +21 -0
  3. data/README.rdoc +55 -0
  4. data/Rakefile +42 -0
  5. data/lib/plastic.rb +85 -0
  6. data/lib/plastic_helper.rb +81 -0
  7. data/test/middlewares/initial.rb +35 -0
  8. data/test/middlewares/intro.rb +18 -0
  9. data/test/middlewares/l337.rb +23 -0
  10. data/test/middlewares/stylizer.rb +17 -0
  11. data/test/rackapp/app.rb +105 -0
  12. data/test/rackapp/config.ru +16 -0
  13. data/test/railsapp/README +243 -0
  14. data/test/railsapp/Rakefile +10 -0
  15. data/test/railsapp/app/controllers/application_controller.rb +10 -0
  16. data/test/railsapp/app/controllers/tommy_boy_controller.rb +9 -0
  17. data/test/railsapp/app/helpers/application_helper.rb +3 -0
  18. data/test/railsapp/app/helpers/tommy_boy_helper.rb +2 -0
  19. data/test/railsapp/app/views/layouts/application.html.erb +13 -0
  20. data/test/railsapp/app/views/tommy_boy/index.html.erb +44 -0
  21. data/test/railsapp/app/views/tommy_boy/more.html.erb +12 -0
  22. data/test/railsapp/config/boot.rb +110 -0
  23. data/test/railsapp/config/database.yml +22 -0
  24. data/test/railsapp/config/environment.rb +50 -0
  25. data/test/railsapp/config/environments/development.rb +17 -0
  26. data/test/railsapp/config/environments/production.rb +28 -0
  27. data/test/railsapp/config/environments/test.rb +28 -0
  28. data/test/railsapp/config/initializers/backtrace_silencers.rb +7 -0
  29. data/test/railsapp/config/initializers/inflections.rb +10 -0
  30. data/test/railsapp/config/initializers/mime_types.rb +5 -0
  31. data/test/railsapp/config/initializers/new_rails_defaults.rb +21 -0
  32. data/test/railsapp/config/initializers/session_store.rb +15 -0
  33. data/test/railsapp/config/locales/en.yml +5 -0
  34. data/test/railsapp/config/routes.rb +4 -0
  35. data/test/railsapp/db/development.sqlite3 +0 -0
  36. data/test/railsapp/db/seeds.rb +7 -0
  37. data/test/railsapp/doc/README_FOR_APP +2 -0
  38. data/test/railsapp/log/development.log +108 -0
  39. data/test/railsapp/log/production.log +0 -0
  40. data/test/railsapp/log/server.log +0 -0
  41. data/test/railsapp/log/test.log +0 -0
  42. data/test/railsapp/public/404.html +30 -0
  43. data/test/railsapp/public/422.html +30 -0
  44. data/test/railsapp/public/500.html +30 -0
  45. data/test/railsapp/public/favicon.ico +0 -0
  46. data/test/railsapp/public/images/rails.png +0 -0
  47. data/test/railsapp/public/javascripts/application.js +2 -0
  48. data/test/railsapp/public/javascripts/controls.js +963 -0
  49. data/test/railsapp/public/javascripts/dragdrop.js +973 -0
  50. data/test/railsapp/public/javascripts/effects.js +1128 -0
  51. data/test/railsapp/public/javascripts/prototype.js +4320 -0
  52. data/test/railsapp/public/robots.txt +5 -0
  53. data/test/railsapp/script/about +4 -0
  54. data/test/railsapp/script/console +3 -0
  55. data/test/railsapp/script/dbconsole +3 -0
  56. data/test/railsapp/script/destroy +3 -0
  57. data/test/railsapp/script/generate +3 -0
  58. data/test/railsapp/script/performance/benchmarker +3 -0
  59. data/test/railsapp/script/performance/profiler +3 -0
  60. data/test/railsapp/script/plugin +3 -0
  61. data/test/railsapp/script/runner +3 -0
  62. data/test/railsapp/script/server +3 -0
  63. data/test/railsapp/test/functional/tommy_boy_controller_test.rb +8 -0
  64. data/test/railsapp/test/performance/browsing_test.rb +9 -0
  65. data/test/railsapp/test/test_helper.rb +38 -0
  66. data/test/railsapp/test/unit/helpers/tommy_boy_helper_test.rb +4 -0
  67. data/test/sinatraapp/app.rb +105 -0
  68. metadata +141 -0
@@ -0,0 +1,2 @@
1
+ 0.0.0 (December 3, 2009)
2
+ * Initial release.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2009 Wyatt M. Greene
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,55 @@
1
+ = Rack::Plastic
2
+
3
+ == Description
4
+
5
+ If you are creating Rack middleware that changes the HTML response, use
6
+ Plastic to get a head start. Plastic takes care of the
7
+ boilerplate Rack glue so that you can focus on simply changing the HTML.
8
+
9
+ == Usage
10
+
11
+ There are two ways you can change the HTML: as a Nokogiri document or as
12
+ a string. Simply define one of the following methods:
13
+
14
+ def change_nokogiri_doc(doc)
15
+ ... insert code that changes the doc ...
16
+ doc
17
+ end
18
+
19
+ def change_html_string(html)
20
+ ... insert code that changes the html string ...
21
+ html
22
+ end
23
+
24
+ If you define both methods, change_nokogiri_doc will be called first, then
25
+ the doc will be converted to an HTML string, then the string will be
26
+ passed to change_html_string.
27
+
28
+ Rack::Plastic also provides some convenience methods for interacting with
29
+ Rack and Nokogiri.
30
+
31
+ == Examples
32
+
33
+ The test/middlewares directory has examples of writing middleware using
34
+ Plastic.
35
+
36
+ == Testing
37
+
38
+ This gem doesn't come with automated tests, but it provides manual tests.
39
+ Each of the example middlewares is inserted into a Sinatra, Rails, and
40
+ Rack test app.
41
+
42
+ To run the Rails test app:
43
+ * cd test/railsapp
44
+ * script/server
45
+ * point your browser to http://localhost:3000
46
+
47
+ To run the Sinatra test app:
48
+ * cd test/sinatraapp
49
+ * ruby app.rb
50
+ * point your browser to http://localhost:4567
51
+
52
+ To run the Rack test app:
53
+ * cd test/rackapp
54
+ * rackup config.ru
55
+ * point your browser to http://localhost:9292
@@ -0,0 +1,42 @@
1
+ require 'rake'
2
+ require 'rake/rdoctask'
3
+
4
+ desc 'Generate documentation for Plastic.'
5
+ Rake::RDocTask.new(:rdoc) do |rdoc|
6
+ rdoc.rdoc_dir = 'rdoc'
7
+ rdoc.title = 'Rack::Plastic'
8
+ rdoc.rdoc_files.include('README.rdoc')
9
+ rdoc.rdoc_files.include('lib/**/*.rb')
10
+ end
11
+
12
+ begin
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |s|
15
+ s.name = "rack-plastic"
16
+ s.version = "0.0.0"
17
+ s.author = "Wyatt Greene"
18
+ s.email = "techiferous@gmail.com"
19
+ s.summary = "Helps you write Rack middleware using Nokogiri."
20
+ s.description = %Q{
21
+ If you are creating Rack middleware that changes the HTML response, use
22
+ Plastic to get a head start. Plastic takes care of the
23
+ boilerplate Rack glue so that you can focus on simply changing the HTML.
24
+ }
25
+ s.add_dependency('rack', '>= 1.0.0')
26
+ s.add_dependency('nokogiri', '>= 1.4.0')
27
+ s.require_path = "lib"
28
+ s.files = []
29
+ s.files << "README.rdoc"
30
+ s.files << "LICENSE"
31
+ s.files << "CHANGELOG"
32
+ s.files << "Rakefile"
33
+ s.files += Dir.glob("lib/**/*")
34
+ s.files += Dir.glob("test/**/*")
35
+ s.homepage = "http://github.com/techiferous/rack-plastic"
36
+ s.requirements << "none"
37
+ s.has_rdoc = true
38
+ end
39
+ Jeweler::GemcutterTasks.new
40
+ rescue LoadError
41
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
42
+ end
@@ -0,0 +1,85 @@
1
+ require 'nokogiri'
2
+
3
+ module Rack
4
+
5
+ # If you are creating Rack middleware that changes the HTML response, inherit
6
+ # from Rack::Plastic to get a head start. Rack::Plastic takes care of the
7
+ # boilerplate Rack glue so that you can focus on simply changing the HTML.
8
+ #
9
+ # There are two ways you can change the HTML: as a Nokogiri document or as
10
+ # a string. Simply define one of the following methods:
11
+ #
12
+ # def change_nokogiri_doc(doc)
13
+ # ... insert code that changes the doc ...
14
+ # doc
15
+ # end
16
+ #
17
+ # def change_html_string(html)
18
+ # ... insert code that changes the html string ...
19
+ # html
20
+ # end
21
+ #
22
+ # If you define both methods, change_nokogiri_doc will be called first, then
23
+ # the doc will be converted to an HTML string, then the string will be
24
+ # passed to change_html_string.
25
+ #
26
+ # Rack::Plastic also provides some convenience methods for interacting with
27
+ # Rack and Nokogiri.
28
+ #
29
+ class Plastic
30
+
31
+ # Rack::Plastic provides an initialize method so that your middleware
32
+ # doesn't have to.
33
+ #
34
+ def initialize(app, options = {}) #:nodoc:
35
+ @app = app
36
+ @options = options
37
+ @p = PlasticHelper.new
38
+ end
39
+
40
+ # Rack::Plastic provides a call method so that your middleware doesn't
41
+ # have to.
42
+ #
43
+ def call(env) #:nodoc:
44
+ @p.send(:handle_request, env, @app, @options, self)
45
+ end
46
+
47
+ private
48
+
49
+ # returns the current request as a Rack::Request object
50
+ #
51
+ def request #:doc:
52
+ @p.request
53
+ end
54
+
55
+ # returns the hash of options that were given to your middleware
56
+ #
57
+ def options #:doc:
58
+ @p.options
59
+ end
60
+
61
+ # a convenience method for adding a new HTML element as the first child
62
+ # of another HTML element
63
+ #
64
+ def add_first_child(parent, new_child) #:doc:
65
+ parent.children.first.add_previous_sibling(new_child)
66
+ end
67
+
68
+ # a convenience method for quickly creating a new HTML element
69
+ #
70
+ def create_node(doc, node_name, content=nil) #:doc:
71
+ node = Nokogiri::XML::Node.new(node_name, doc)
72
+ node.content = content if content
73
+ node
74
+ end
75
+
76
+ # Nokogiri's node.content=(text) method automatically HTML escapes the given text.
77
+ # This can cause problems. This method updates the text of an HTML element
78
+ # without escaping the text.
79
+ #
80
+ def update_text(node, new_text) #:doc:
81
+ node.send(:native_content=, new_text)
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,81 @@
1
+ require 'nokogiri'
2
+
3
+ module Rack
4
+
5
+ # PlasticHelper was created to separate Plastic's implementation from Plastic's
6
+ # interface.
7
+ #
8
+ # This class basically contains all of the Rack code that you'd have to write every
9
+ # time you wanted to write a new middleware that modifies the HTML response.
10
+ #
11
+ class PlasticHelper #:nodoc:
12
+
13
+ def request
14
+ @request
15
+ end
16
+
17
+ def options
18
+ @options
19
+ end
20
+
21
+ private
22
+
23
+ def handle_request(env, app, options, plastic)
24
+ @app = app
25
+ @options = options
26
+ @request = Rack::Request.new(env)
27
+ status, @headers, @body = @app.call(env)
28
+ if html?
29
+ if plastic.respond_to? :change_nokogiri_doc
30
+ doc = Nokogiri::HTML(body_to_string)
31
+ doc = plastic.send(:change_nokogiri_doc, doc)
32
+ if !doc.is_a?(Nokogiri::XML::Document)
33
+ raise "You must return a Nokogiri::XML::Document object from change_nokogiri_doc."
34
+ end
35
+ new_body_string = doc.to_html
36
+ else
37
+ new_body_string = body_to_string
38
+ end
39
+ if plastic.respond_to? :change_html_string
40
+ new_body_string = plastic.send(:change_html_string, new_body_string)
41
+ if !new_body_string.is_a?(String)
42
+ raise "You must return a String from change_html_string."
43
+ end
44
+ end
45
+ update_response_body(new_body_string)
46
+ update_content_length
47
+ end
48
+ [status, @headers, @body]
49
+ end
50
+
51
+ def html?
52
+ @headers["Content-Type"] && @headers["Content-Type"].include?("text/html")
53
+ end
54
+
55
+ def body_to_string
56
+ s = ""
57
+ @body.each { |x| s << x }
58
+ s
59
+ end
60
+
61
+ def update_response_body(new_body_string)
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 = new_body_string
66
+ else
67
+ @body = [new_body_string]
68
+ end
69
+ end
70
+
71
+ def update_content_length
72
+ length = 0
73
+ @body.each do |s| # we can't use inject because @body may not respond to it
74
+ length += Rack::Utils.bytesize(s) # we use Rack::Utils.bytesize to avoid
75
+ # incompatibilities between Ruby 1.8 and 1.9
76
+ end
77
+ @headers['Content-Length'] = length.to_s
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,35 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'plastic')
2
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'plastic_helper')
3
+
4
+ # This middleware emphasizes the first character in every paragraph, not unlike
5
+ # the initials in illuminated manuscripts of the Middle Ages.
6
+ #
7
+ module Rack
8
+ class Initial < Plastic
9
+
10
+ def change_nokogiri_doc(doc)
11
+ doc.css("p").each do |p|
12
+ p.traverse do |node|
13
+ if node.text?
14
+ if node.content =~ /(.*?)(\S)(.*)/m
15
+ initial_whitespace = $1
16
+ initial_character = $2
17
+ rest_of_text = $3
18
+ update_text(node, initial_whitespace + "openingspantag" + initial_character +
19
+ "closingspantag" + rest_of_text)
20
+ end
21
+ break
22
+ end
23
+ end
24
+ end
25
+ doc
26
+ end
27
+
28
+ def change_html_string(html)
29
+ html.gsub!(/openingspantag/, '<span style="font-size: 150%; font-weight: bold;">')
30
+ html.gsub!(/closingspantag/, '</span>')
31
+ html
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'plastic')
2
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'plastic_helper')
3
+
4
+ # This middleware demonstrates how you would add an HTML element to the beginning
5
+ # of a web page.
6
+ #
7
+ module Rack
8
+ class Intro < Plastic
9
+
10
+ def change_nokogiri_doc(doc)
11
+ h1 = create_node(doc, "h1", "Holy shnikes!")
12
+ h1['style'] = "text-align: center;"
13
+ add_first_child(doc.at_css("body"), h1)
14
+ doc
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'plastic')
2
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'plastic_helper')
3
+
4
+ # This middleware converts the text of every paragraph to leetspeak.
5
+ #
6
+ module Rack
7
+ class L337 < Plastic
8
+
9
+ def change_nokogiri_doc(doc)
10
+ doc.css("p").each do |p|
11
+ p.traverse do |node|
12
+ if node.text?
13
+ l337_text = node.content.upcase.tr('ABCDEFGHIJKLMNOPQRSTUVWXYZ',
14
+ '48CD3F6H1JKLMN0P9R57UVWxY2')
15
+ update_text(node, l337_text)
16
+ end
17
+ end
18
+ end
19
+ doc
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'plastic')
2
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'plastic_helper')
3
+
4
+ # This middleware demonstrates how to add inline CSS styles to the web page.
5
+ #
6
+ module Rack
7
+ class Stylizer < Plastic
8
+
9
+ def change_nokogiri_doc(doc)
10
+ doc.at_css("body")["style"] = "font-family: Georgia, serif; font-style: italic;"
11
+ doc.at_css("div#container")["style"] =
12
+ "margin-left:auto;margin-right:auto;width:500px;position:relative"
13
+ doc
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,105 @@
1
+ class App
2
+
3
+ def call(env)
4
+ response = Rack::Response.new
5
+ request = Rack::Request.new(env)
6
+ response['Content-Type'] = 'text/html'
7
+ if request.path =~ /more/
8
+ response.write more
9
+ else
10
+ response.write front_page
11
+ end
12
+ response.finish
13
+ end
14
+
15
+ def front_page
16
+ %Q{
17
+ <!DOCTYPE html
18
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
19
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
20
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
21
+ <head>
22
+ <title>The Greatest Movie of All Time</title>
23
+ </head>
24
+ <body>
25
+ <div id="container">
26
+ <p>
27
+ What my associate is trying to say is that our new brake pads are really cool.
28
+ You're not even gonna believe it.
29
+ </p>
30
+ <p>
31
+ Like, um, let's say you're driving along
32
+ the road, with your family.<br />
33
+ And you're driving along...la de da...woo...<br />
34
+ And then all of a sudden
35
+ there's a truck tire
36
+ in the middle of the road
37
+ and you hit the brakes.<br />
38
+ Screeeee!
39
+ </p>
40
+ <p>
41
+ Woah, that was close.
42
+ </p>
43
+ <p>
44
+ Now let's see what happens when you're
45
+ driving with "the other guy's brake pads".
46
+ </p>
47
+ <p>
48
+ You're driving along,<br />
49
+ you're driving along,<br />
50
+ and all of a sudden your kids are
51
+ yelling from the back seat:<br />
52
+ "I gotta go to the bathroom, daddy!"<br />
53
+ "Not now, dammit!"<br />
54
+ "Truck tire! I can't stop! Aaaaa! Help!"<br />
55
+ "There's a cliff! Aaaaa!"<br />
56
+ And your family screaming:<br />
57
+ "Oh my God, we're burning alive!"<br />
58
+ "No! I can't feel my legs!"<br />
59
+ Here comes the meat-wagon! Woo woo woo!<br />
60
+ And the medic gets out and says:<br />
61
+ "Oh! My! God!"<br />
62
+ New guy's in the corner puking his guts out:<br />
63
+ Blllleeeeeeeaaaaaaaaaaah!<br />
64
+ Blllleeeeeeeaaaaaaaaaaah!<br />
65
+ </p>
66
+ <p>
67
+ All because you wanna save a coupla extra pennies.
68
+ </p>
69
+ <a href="/more">&laquo; inflict me with more &raquo;</a>
70
+ </div>
71
+ </body>
72
+ </html>
73
+ }
74
+ end
75
+
76
+ def more
77
+ %Q{
78
+ <!DOCTYPE html
79
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
80
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
81
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
82
+ <head>
83
+ <title>More of the Greatest Movie of All Time</title>
84
+ </head>
85
+ <body>
86
+ <div id="container">
87
+ <p>
88
+ D+? Oh my God! I passed! I passed! Oh, man i got a D+! I'm gonna graduate!
89
+ I'm gonna graduate! D+!
90
+ </p>
91
+ <p>
92
+ Hey guys, do i look different now that i'm a college grad?
93
+ </p>
94
+ <p>
95
+ Apparently they give a lot fewer D+'s than D-'s.
96
+ It's not a grade they like to give out, i'll tell ya that right now.
97
+ </p>
98
+ <a href="/">&laquo; take me back &raquo;</a>
99
+ </div>
100
+ </body>
101
+ </html>
102
+ }
103
+ end
104
+
105
+ end