rack-nokogiri 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 943e6fbfd41f3f67d8da5da8e3dd2c1be8ccdd9c
4
+ data.tar.gz: 923c33ec16218112d786370b6d43de937b3e1abd
5
+ SHA512:
6
+ metadata.gz: 092d69bd42defc30b27566b120429a929ffbef253e6309c10d162175aa9f40c335602a0ee930418fa7b0ea97a5e0ef460041bb290bc7682c15d748cba4931180
7
+ data.tar.gz: a8a051762ae0cb1cb7eb496a1b6ad87bc0193db9dda006bbd6b955327dd58dfcafd1cf564aeebe44077cc3f623ddb37e384d4dced9d580230ed8402b962011f6
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rack-highlighter.gemspec
4
+ gemspec
@@ -0,0 +1,5 @@
1
+ guard 'minitest' do
2
+ watch(%r{^spec/(.*)_spec\.rb})
3
+ watch(%r{^lib/rack/(.*)([^/]+)\.rb}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
4
+ watch(%r{^spec/spec_helper\.rb}) { "spec" }
5
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Daniel Perez Alvarez
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,103 @@
1
+ # Rack::Nokogiri [![Build Status](https://secure.travis-ci.org/unindented/rack-nokogiri.png)](http://travis-ci.org/unindented/rack-nokogiri) [![Dependency Status](https://gemnasium.com/unindented/rack-nokogiri.png)](https://gemnasium.com/unindented/rack-nokogiri)
2
+
3
+ Rack Middleware that allows you to manipulate the nodes in your HTML response however you like.
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's `Gemfile`:
9
+
10
+ ```ruby
11
+ gem 'rack-nokogiri'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ ```sh
17
+ $ bundle
18
+ ```
19
+
20
+ Or install it yourself as:
21
+
22
+ ```sh
23
+ $ gem install rack-nokogiri
24
+ ```
25
+
26
+
27
+ ## Usage
28
+
29
+ ### Adding Rack::Nokogiri to a Rails application
30
+
31
+ To wrap all `<p>` with class `target` with a `div`, we could do something like this:
32
+
33
+ ```ruby
34
+ require 'rack/nokogiri'
35
+
36
+ class Application < Rails::Application
37
+ config.middleware.use Rack::Nokogiri, css: 'p.target' do |nodes|
38
+ nodes.wrap '<div class="wrapper"></div>'
39
+ end
40
+ end
41
+ ```
42
+
43
+ If we wanted to use XPath instead of CSS selectors, we could do this instead:
44
+
45
+ ```ruby
46
+ require 'rack/nokogiri'
47
+
48
+ class Application < Rails::Application
49
+ config.middleware.use Rack::Nokogiri, xpath: "//p[@class='target']" do |nodes|
50
+ nodes.wrap '<div class="wrapper"></div>'
51
+ end
52
+ end
53
+ ```
54
+
55
+ ### Adding Rack::Nokogiri to a Sinatra application
56
+
57
+ For Sinatra we would do:
58
+
59
+ ```ruby
60
+ require 'sinatra'
61
+ require 'rack/nokogiri'
62
+
63
+ use Rack::Nokogiri, css: 'p.target' do |nodes|
64
+ nodes.wrap '<div class="wrapper"></div>'
65
+ end
66
+
67
+ get('/') do
68
+ '<p class="target">Hello World!</p>'
69
+ end
70
+ ```
71
+
72
+ ### Adding Rack::Nokogiri to a Rackup application
73
+
74
+ For a Rackup app we would do:
75
+
76
+ ```ruby
77
+ require 'rack'
78
+ require 'rack/nokogiri'
79
+
80
+ use Rack::Nokogiri, css: 'p.target' do |nodes|
81
+ nodes.wrap '<div class="wrapper"></div>'
82
+ end
83
+
84
+ run lambda { |env|
85
+ [200, {'Content-Type' => 'text/html'}, ['<p class="target">Hello World!</p>']]
86
+ }
87
+ ```
88
+
89
+
90
+ ## Meta
91
+
92
+ * Code: `git clone git://github.com/unindented/rack-nokogiri.git`
93
+ * Home: <https://github.com/unindented/rack-nokogiri/>
94
+
95
+
96
+ ## Contributors
97
+
98
+ * Daniel Perez Alvarez ([unindented@gmail.com](mailto:unindented@gmail.com))
99
+
100
+
101
+ ## License
102
+
103
+ Copyright (c) 2013 Daniel Perez Alvarez ([unindented.org](http://unindented.org/)). This is free software, and may be redistributed under the terms specified in the LICENSE file.
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ # Test tasks.
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.pattern = 'spec/*_spec.rb'
8
+ end
9
+
10
+ # Default task.
11
+
12
+ task default: :test
@@ -0,0 +1,53 @@
1
+ require 'rack/nokogiri/version'
2
+
3
+ require 'rack'
4
+ require 'nokogiri'
5
+
6
+ module Rack
7
+ class Nokogiri
8
+ include Rack::Utils
9
+
10
+ def initialize(app, opts = {}, &block)
11
+ @app = app
12
+ @opts = opts.select {|key, value| [:css, :xpath].include?(key) }
13
+ @block = block
14
+ end
15
+
16
+ def call(env)
17
+ status, headers, response = @app.call(env)
18
+ headers = HeaderHash.new(headers)
19
+
20
+ if should_process?(status, headers)
21
+ content = extract_content(response)
22
+
23
+ doc = ::Nokogiri::HTML(content)
24
+ process_nodes(doc)
25
+ content = doc.to_html
26
+
27
+ headers['content-length'] = bytesize(content).to_s
28
+ response = [content]
29
+ end
30
+
31
+ [status, headers, response]
32
+ end
33
+
34
+ def should_process?(status, headers)
35
+ !STATUS_WITH_NO_ENTITY_BODY.include?(status) &&
36
+ !headers['transfer-encoding'] &&
37
+ headers['content-type'] &&
38
+ headers['content-type'].include?('text/html')
39
+ end
40
+
41
+ def extract_content(response)
42
+ response.reduce('') { |memo, part| memo + part }
43
+ end
44
+
45
+ def process_nodes(doc)
46
+ nodes = ::Nokogiri::XML::NodeSet.new(doc)
47
+ nodes += doc.css(@opts[:css]) unless @opts[:css].nil?
48
+ nodes += doc.xpath(@opts[:xpath]) unless @opts[:xpath].nil?
49
+ @block.call(nodes) unless nodes.empty?
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ class Nokogiri
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'rack/nokogiri/version'
6
+
7
+ Gem::Specification.new do |gem|
8
+ gem.name = 'rack-nokogiri'
9
+ gem.version = Rack::Nokogiri::VERSION
10
+ gem.authors = ['Daniel Perez Alvarez']
11
+ gem.email = ['unindented@gmail.com']
12
+ gem.description = %q{Rack Middleware for node manipulation.}
13
+ gem.summary = %q{Rack Middleware that allows you to manipulate the nodes in your response however you like.}
14
+ gem.homepage = 'http://github.com/unindented/rack-nokogiri'
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ['lib']
20
+
21
+ gem.required_ruby_version = '>= 1.9.0'
22
+
23
+ gem.add_runtime_dependency 'rack', '>= 1.0.0'
24
+ gem.add_runtime_dependency 'nokogiri', '>= 1.4.0'
25
+
26
+ gem.add_development_dependency 'rake'
27
+ gem.add_development_dependency 'minitest'
28
+ gem.add_development_dependency 'minitest-reporters'
29
+ gem.add_development_dependency 'rack-test'
30
+
31
+ gem.add_development_dependency 'guard-minitest'
32
+ gem.add_development_dependency 'rb-inotify'
33
+ gem.add_development_dependency 'rb-fsevent'
34
+ gem.add_development_dependency 'rb-fchange'
35
+ end
@@ -0,0 +1,105 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe Rack::Nokogiri do
4
+
5
+ let(:app) do
6
+ create_app(status, headers, content, options) do |nodes|
7
+ nodes.wrap('<div class="greeting"></div>')
8
+ end
9
+ end
10
+
11
+ before do
12
+ get '/'
13
+ end
14
+
15
+ describe 'with a content-type other than `text/html`' do
16
+
17
+ let(:status) { 200 }
18
+ let(:headers) do
19
+ {
20
+ 'Content-Type' => 'text/plain',
21
+ 'Content-Length' => content.length.to_s
22
+ }
23
+ end
24
+
25
+ let(:content) { 'foobar' }
26
+ let(:options) { {} }
27
+
28
+ it 'leaves the status untouched' do
29
+ last_response.status.must_equal status
30
+ end
31
+
32
+ it 'leaves the headers untouched' do
33
+ last_response.headers.must_equal headers
34
+ end
35
+
36
+ it 'leaves the content untouched' do
37
+ last_response.body.must_equal content
38
+ end
39
+
40
+ end
41
+
42
+ describe 'with a content-type of `text/html`' do
43
+
44
+ let(:status) { 200 }
45
+ let(:headers) do
46
+ {
47
+ 'Content-Type' => 'text/html',
48
+ 'Content-Length' => content.length.to_s
49
+ }
50
+ end
51
+
52
+ let(:content) do
53
+ <<-eos
54
+ <!DOCTYPE html>
55
+ <html lang="en">
56
+ <head>
57
+ <meta charset="utf-8" />
58
+ <title>Some HTML</title>
59
+ </head>
60
+
61
+ <body>
62
+ <p class="hi">Hi!</p>
63
+ <p class="bye">Bye!</p>
64
+ </body>
65
+ </html>
66
+ eos
67
+ end
68
+
69
+ describe 'with a CSS selector' do
70
+ let(:options) { { css: 'p.hi' } }
71
+
72
+ it 'leaves the status untouched' do
73
+ last_response.status.must_equal status
74
+ end
75
+
76
+ it 'updates the headers with the new `Content-Length`' do
77
+ last_response.headers.wont_equal headers
78
+ end
79
+
80
+ it 'executes the block on the results of the selector' do
81
+ last_response.body.must_have_css ".greeting .hi"
82
+ last_response.body.wont_have_css ".greeting .bye"
83
+ end
84
+ end
85
+
86
+ describe 'with a XPath selector' do
87
+ let(:options) { { xpath: "//p[@class='hi']" } }
88
+
89
+ it 'leaves the status untouched' do
90
+ last_response.status.must_equal status
91
+ end
92
+
93
+ it 'updates the headers with the new `Content-Length`' do
94
+ last_response.headers.wont_equal headers
95
+ end
96
+
97
+ it 'executes the block on the results of the selector' do
98
+ last_response.body.must_have_xpath "//div[@class='greeting']/p[@class='hi']"
99
+ last_response.body.wont_have_xpath "//div[@class='greeting']/p[@class='bye']"
100
+ end
101
+ end
102
+
103
+ end
104
+
105
+ end
@@ -0,0 +1,16 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/reporters'
3
+ require 'rack/test'
4
+ require 'nokogiri'
5
+
6
+ require File.expand_path('../support/expectations', __FILE__)
7
+ require File.expand_path('../../lib/rack/nokogiri', __FILE__)
8
+
9
+ include Rack::Test::Methods
10
+
11
+ MiniTest::Reporters.use! MiniTest::Reporters::SpecReporter.new
12
+
13
+ def create_app(status, headers, content, options, &block)
14
+ app = lambda { |env| [status, headers, [content]] }
15
+ Rack::Nokogiri.new(app, options, &block)
16
+ end
@@ -0,0 +1,33 @@
1
+ module MiniTest::Assertions
2
+
3
+ def assert_has_css(html, css)
4
+ assert ::Nokogiri::HTML(html).css(css).length > 0,
5
+ "Expected HTML to produce results for CSS selector `#{css}`"
6
+ end
7
+
8
+ def refute_has_css(html, css)
9
+ refute ::Nokogiri::HTML(html).css(css).length > 0,
10
+ "Expected HTML to produce no results for CSS selector `#{css}`"
11
+ end
12
+
13
+ def assert_has_xpath(html, xpath)
14
+ assert ::Nokogiri::HTML(html).xpath(xpath).length > 0,
15
+ "Expected HTML to produce results for XPath selector `#{xpath}`"
16
+ end
17
+
18
+ def refute_has_xpath(html, xpath)
19
+ refute ::Nokogiri::HTML(html).xpath(xpath).length > 0,
20
+ "Expected HTML to produce no results for XPath selector `#{xpath}`"
21
+ end
22
+
23
+ end
24
+
25
+ module MiniTest::Expectations
26
+
27
+ infect_an_assertion :assert_has_css, :must_have_css, :reverse
28
+ infect_an_assertion :refute_has_css, :wont_have_css, :reverse
29
+
30
+ infect_an_assertion :assert_has_xpath, :must_have_xpath, :reverse
31
+ infect_an_assertion :refute_has_xpath, :wont_have_xpath, :reverse
32
+
33
+ end
metadata ADDED
@@ -0,0 +1,200 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-nokogiri
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Perez Alvarez
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.4.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.4.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest-reporters
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rack-test
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rb-inotify
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rb-fsevent
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rb-fchange
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: Rack Middleware for node manipulation.
154
+ email:
155
+ - unindented@gmail.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - .gitignore
161
+ - .travis.yml
162
+ - Gemfile
163
+ - Guardfile
164
+ - LICENSE
165
+ - README.md
166
+ - Rakefile
167
+ - lib/rack/nokogiri.rb
168
+ - lib/rack/nokogiri/version.rb
169
+ - rack-nokogiri.gemspec
170
+ - spec/nokogiri_spec.rb
171
+ - spec/spec_helper.rb
172
+ - spec/support/expectations.rb
173
+ homepage: http://github.com/unindented/rack-nokogiri
174
+ licenses: []
175
+ metadata: {}
176
+ post_install_message:
177
+ rdoc_options: []
178
+ require_paths:
179
+ - lib
180
+ required_ruby_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - '>='
183
+ - !ruby/object:Gem::Version
184
+ version: 1.9.0
185
+ required_rubygems_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - '>='
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ requirements: []
191
+ rubyforge_project:
192
+ rubygems_version: 2.0.5
193
+ signing_key:
194
+ specification_version: 4
195
+ summary: Rack Middleware that allows you to manipulate the nodes in your response
196
+ however you like.
197
+ test_files:
198
+ - spec/nokogiri_spec.rb
199
+ - spec/spec_helper.rb
200
+ - spec/support/expectations.rb