butternut 0.0.1 → 0.1.0

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/Rakefile CHANGED
@@ -33,7 +33,7 @@ Spec::Rake::SpecTask.new(:rcov) do |spec|
33
33
  spec.rcov = true
34
34
  end
35
35
 
36
- task :spec => :check_dependencies
36
+ task :spec => [:check_dependencies, "tmp:clear"]
37
37
 
38
38
  task :default => :spec
39
39
 
@@ -51,3 +51,11 @@ desc 'Generate the css for the html formatter from sass'
51
51
  task :sass do
52
52
  sh 'sass -t expanded lib/butternut/cucumber.sass > lib/butternut/cucumber.css'
53
53
  end
54
+
55
+ namespace :tmp do
56
+ desc 'Delete temporary files'
57
+ task :clear do
58
+ require 'fileutils'
59
+ FileUtils.rm_rf(Dir.glob(File.dirname(__FILE__) + "/tmp/features/*"), :verbose => true)
60
+ end
61
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.1.0
data/butternut.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{butternut}
8
- s.version = "0.0.1"
8
+ s.version = "0.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jeremy Stephens"]
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
34
34
  "spec/butternut/helpers_spec.rb",
35
35
  "spec/butternut_spec.rb",
36
36
  "spec/fixtures/css/bar.css",
37
+ "spec/fixtures/facepalm.jpg",
37
38
  "spec/fixtures/foo.css",
38
39
  "spec/fixtures/foo.html",
39
40
  "spec/fixtures/foo.js",
@@ -1,10 +1,12 @@
1
1
  require 'cucumber/formatter/ordered_xml_markup'
2
2
  require 'cucumber/formatter/duration'
3
+
3
4
  require 'tmpdir'
4
5
  require 'fileutils'
5
6
  require 'nokogiri'
6
7
  require 'uri'
7
8
  require 'open-uri'
9
+ require 'net/ftp' # For Net::FTPPermError
8
10
 
9
11
  module Butternut
10
12
  class Formatter
@@ -414,42 +416,25 @@ module Butternut
414
416
  end
415
417
 
416
418
  def transform_page_source(page_source, page_url)
417
- page_uri = URI.parse(page_url)
418
- page_uri.query = nil
419
- collected_files = []
419
+ base_uri = URI.parse(page_url)
420
+ base_uri.query = nil
421
+ @already_collected = []
420
422
 
421
423
  doc = Nokogiri.HTML(page_source)
422
- { 'img' => 'src',
423
- 'link[rel=stylesheet]' => 'href'
424
- }.each_pair do |selector, attr|
424
+ { :image => ['img', 'src'],
425
+ :stylesheet => ['link[rel=stylesheet]', 'href']
426
+ }.each_pair do |type, (selector, attr)|
425
427
  doc.css(selector).each do |elt|
426
428
  elt_url = elt[attr]
427
- next if elt_url.nil?
428
-
429
- elt_url.gsub!('\\"', "")
430
- next if elt_url.empty?
431
- next if collected_files.index(elt_url)
432
-
433
- basename = File.basename(elt_url)
434
- local_file = File.join(@source_output_dir, basename)
435
- remote_file = case elt_url
436
- when %r{^\w+://} then elt_url
437
- when %r{^/} then
438
- "#{page_uri.scheme}://#{page_uri.host}:#{page_uri.port}#{elt_url}"
439
- else
440
- page_url.to_s + "/" + elt_url
441
- end
442
- File.open(local_file, "w") { |f| f.write open(remote_file).read }
443
- collected_files << elt_url
444
-
445
- elt[attr] = basename
429
+ next if elt_url.nil? || elt_url.empty?
430
+
431
+ result = save_remote_file(base_uri, type, elt_url)
432
+ elt[attr] = result if result
446
433
  end
447
434
  end
448
435
 
449
436
  # disable links
450
- doc.css('a').each do |link|
451
- link['href'] = "#"
452
- end
437
+ doc.css('a').each { |link| link['href'] = "#" }
453
438
 
454
439
  # turn off scripts
455
440
  doc.css('script').each { |s| s.unlink }
@@ -459,5 +444,32 @@ module Butternut
459
444
 
460
445
  doc.to_s
461
446
  end
447
+
448
+ def transform_stylesheet(stylesheet_uri, content)
449
+ content.gsub(%r{url\(([^\)]+)\)}) do |_|
450
+ result = save_remote_file(stylesheet_uri, :image, $1)
451
+ "url(#{result || $1})"
452
+ end
453
+ end
454
+
455
+ def save_remote_file(base_uri, type, url)
456
+ # FIXME: two different files could have the same basename :)
457
+ uri = URI.parse(url)
458
+ remote_uri = uri.absolute? ? uri : base_uri.merge(uri)
459
+ basename = File.basename(uri.path)
460
+
461
+ unless @already_collected.include?(remote_uri)
462
+ begin
463
+ content = open(remote_uri.to_s).read
464
+ content = transform_stylesheet(remote_uri, content) if type == :stylesheet
465
+ local_path = File.join(@source_output_dir, basename)
466
+ File.open(local_path, "w") { |f| f.write(content) }
467
+ @already_collected << remote_uri
468
+ rescue Errno::ENOENT, OpenURI::HTTPError, Net::FTPPermError
469
+ return nil
470
+ end
471
+ end
472
+ basename
473
+ end
462
474
  end
463
475
  end
@@ -12,6 +12,12 @@ module Butternut
12
12
  end
13
13
  end
14
14
 
15
+ Spec::Matchers.define :be_an_existing_file do
16
+ match do |filename|
17
+ File.exist?(filename)
18
+ end
19
+ end
20
+
15
21
  def setup_formatter(options = {})
16
22
  @out = StringIO.new
17
23
  @formatter = Butternut::Formatter.new(step_mother, @out, options)
@@ -232,15 +238,15 @@ module Butternut
232
238
 
233
239
  describe "displaying page source to file" do
234
240
  before(:each) do
235
- @tmpdir = File.join(File.dirname(__FILE__), "..", "..", "tmp")
241
+ dir = File.join(File.dirname(__FILE__), "..", "..", "tmp")
236
242
  setup_formatter({:formats => [
237
- ['Butternut::Formatter', File.join(@tmpdir, "main", "huge.html")]
243
+ ['Butternut::Formatter', File.join(dir, "main", "huge.html")]
238
244
  ]})
239
245
  run_defined_feature
240
246
  @doc = Nokogiri.HTML(@out.string)
241
247
 
242
- dir = File.join(@tmpdir, "features", Date.today.to_s)
243
- file = most_recent_html_file(dir)
248
+ @tmp_dir = File.join(dir, "features", Date.today.to_s)
249
+ file = most_recent_html_file(@tmp_dir)
244
250
  @page_doc = Nokogiri.HTML(open(file).read)
245
251
  end
246
252
 
@@ -264,9 +270,20 @@ module Butternut
264
270
  end
265
271
 
266
272
  it "saves images and stylesheets and rewrites urls in page source" do
267
- @page_doc.at('img')['src'].should == "picard.jpg"
268
- @page_doc.at('link:first[rel="stylesheet"]')['href'].should == "foo.css"
269
- @page_doc.at('link:last[rel="stylesheet"]')['href'].should == "bar.css"
273
+ @page_doc.at('img:nth(1)')['src'].should == "picard.jpg"
274
+ File.join(@tmp_dir, "picard.jpg").should be_an_existing_file
275
+
276
+ @page_doc.at('link:nth(1)[rel="stylesheet"]')['href'].should == "foo.css"
277
+ File.join(@tmp_dir, "foo.css").should be_an_existing_file
278
+
279
+ @page_doc.at('link:nth(2)[rel="stylesheet"]')['href'].should == "bar.css"
280
+ File.join(@tmp_dir, "bar.css").should be_an_existing_file
281
+ end
282
+
283
+ it "saves assets and rewrites urls referred to by stylesheets" do
284
+ foo = open(File.join(@tmp_dir, "foo.css")).read
285
+ foo.should include("url(facepalm.jpg)")
286
+ File.join(@tmp_dir, "facepalm.jpg").should be_an_existing_file
270
287
  end
271
288
 
272
289
  it "turns off links" do
@@ -284,6 +301,18 @@ module Butternut
284
301
  elt['disabled'].should == "disabled"
285
302
  end
286
303
  end
304
+
305
+ it "handles Errno::ENOENT" do
306
+ @page_doc.at('img:nth(2)')['src'].should == "/roflpwnage/missing_file_omg.gif"
307
+ end
308
+
309
+ it "handles OpenURI::HTTPError" do
310
+ @page_doc.at('img:nth(3)')['src'].should == "http://google.com/missing_file_omg.gif"
311
+ end
312
+
313
+ it "handles Net::FTPPermError" do
314
+ @page_doc.at('img:nth(4)')['src'].should == "ftp://mirror.anl.gov/missing_file_omg.gif"
315
+ end
287
316
  end
288
317
  end
289
318
  end
Binary file
@@ -1,3 +1,9 @@
1
1
  body {
2
2
  font-family: Verdana;
3
3
  }
4
+
5
+ .facepalm {
6
+ width: 750px;
7
+ height: 600px;
8
+ background: url(../fixtures/facepalm.jpg);
9
+ }
@@ -2,7 +2,7 @@
2
2
  <head>
3
3
  <title>Foo</title>
4
4
  <link rel="stylesheet" href="foo.css" type="text/css"/>
5
- <link rel="stylesheet" href="/css/bar.css" type="text/css"/>
5
+ <link rel="stylesheet" href="css/bar.css" type="text/css"/>
6
6
  <script type="text/javascript" src="foo.js"></script>
7
7
  </head>
8
8
  <body>
@@ -17,5 +17,10 @@
17
17
  <textarea name="yar"></textarea>
18
18
  <input type="submit" value="Submit" />
19
19
  </form>
20
+ <img src="/roflpwnage/missing_file_omg.gif"/>
21
+ <img src="http://google.com/missing_file_omg.gif"/>
22
+ <img src="ftp://mirror.anl.gov/missing_file_omg.gif"/>
23
+
24
+ <div class="facepalm">&nbsp;</div>
20
25
  </body>
21
26
  </html>
data/spec/spec.opts CHANGED
@@ -1 +1,2 @@
1
1
  --color
2
+ --backtrace
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: butternut
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Stephens
@@ -79,6 +79,7 @@ files:
79
79
  - spec/butternut/helpers_spec.rb
80
80
  - spec/butternut_spec.rb
81
81
  - spec/fixtures/css/bar.css
82
+ - spec/fixtures/facepalm.jpg
82
83
  - spec/fixtures/foo.css
83
84
  - spec/fixtures/foo.html
84
85
  - spec/fixtures/foo.js