monet 0.2.3 → 0.2.5
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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +7 -0
- data/Gemfile +1 -1
- data/lib/monet/baseless_image.rb +5 -1
- data/lib/monet/baseline_control.rb +30 -17
- data/lib/monet/capture.rb +28 -27
- data/lib/monet/capture_map.rb +11 -3
- data/lib/monet/changeset.rb +4 -0
- data/lib/monet/config.rb +18 -11
- data/lib/monet/image.rb +67 -0
- data/lib/monet/router.rb +71 -0
- data/lib/monet/tasks.rb +10 -7
- data/lib/monet/version.rb +1 -1
- data/lib/monet.rb +4 -29
- data/spec/capture_map_spec.rb +5 -50
- data/spec/capture_spec.rb +59 -33
- data/spec/cassettes/spider-config.yml +33784 -0
- data/spec/cassettes/spider-map.yml +33782 -0
- data/spec/config_spec.rb +14 -8
- data/spec/fixtures/baselines/lance.com/.DS_Store +0 -0
- data/spec/fixtures/baselines/lance.com/lance.com-1024-diff.png +0 -0
- data/spec/fixtures/baselines/lance.com/lance.com-1024.png +0 -0
- data/spec/fixtures/baselines/lance.com/lance.com|aboutus-1024.png +0 -0
- data/spec/fixtures/captures/lance.com/lance.com-1024.png +0 -0
- data/spec/fixtures/spider-config.yaml +8 -0
- data/spec/fixtures/thumbnails/lance.com/.DS_Store +0 -0
- data/spec/fixtures/thumbnails/lance.com/lance.com-1024.png +0 -0
- data/spec/image_spec.rb +36 -0
- data/spec/router_spec.rb +90 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/tmp/test.png +0 -0
- metadata +31 -7
- data/lib/monet/path_router.rb +0 -70
- data/spec/cassettes/spider.yml +0 -28572
- data/spec/path_router_spec.rb +0 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4245512ca8fcbcf954b6e276d7dc978c9a680444
|
4
|
+
data.tar.gz: 19dd5cf3f272708cb87754604cc7902d33501144
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac0adb807b480ab762d914312f79938df763d165c52a0c43586cccd11c8b680863df007d7fd3fe132b6b33d4469e3104795fcf17924f9fa4fd287475294176b3
|
7
|
+
data.tar.gz: 95da6332f5b6d0af5ce48980ceedd1535ea21d472ac11c42e938a6fae25bf1b472efa6a74fd1739a61ab7afb1349bf6f5445d6800244e5f4a7b91ae3fc4de87c
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.0
|
1
|
+
2.0.0-p247
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/lib/monet/baseless_image.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'monet/
|
1
|
+
require 'monet/image'
|
2
2
|
require 'monet/changeset'
|
3
3
|
require 'monet/baseless_image'
|
4
4
|
require 'monet/compare'
|
@@ -11,20 +11,18 @@ module Monet
|
|
11
11
|
attr_reader :flags
|
12
12
|
|
13
13
|
def initialize(config)
|
14
|
-
@
|
15
|
-
@baseline_dir = config.baseline_dir
|
14
|
+
@config = config
|
16
15
|
|
17
16
|
strategy = Monet.const_get(config.compare_type)
|
18
17
|
|
18
|
+
@router = Monet::Router.new config
|
19
19
|
@comparer = Monet::Compare.new(strategy)
|
20
|
-
@router = Monet::PathRouter.new(config)
|
21
20
|
@flags = []
|
22
21
|
end
|
23
22
|
|
24
23
|
def run
|
25
|
-
captures.each do |
|
26
|
-
|
27
|
-
compare @comparer.compare(baseline_path, capture)
|
24
|
+
captures.each do |img|
|
25
|
+
compare @comparer.compare(@router.baseline_dir(img.name), img.path)
|
28
26
|
end
|
29
27
|
|
30
28
|
@flags
|
@@ -40,29 +38,44 @@ module Monet
|
|
40
38
|
end
|
41
39
|
|
42
40
|
def captures
|
43
|
-
Dir.glob
|
41
|
+
files = Dir.glob(File.join(@config.capture_dir, @config.site, "*.png"))
|
42
|
+
files.map do |path|
|
43
|
+
Monet::Image.new(path)
|
44
|
+
end
|
44
45
|
end
|
45
46
|
|
46
47
|
def discard(path)
|
47
48
|
puts "discarding #{path}"
|
48
|
-
FileUtils.remove(path)
|
49
|
+
FileUtils.remove(path) if File.exists?(path)
|
49
50
|
end
|
50
51
|
|
51
52
|
def baseline(diff)
|
52
|
-
|
53
|
-
to = site_dir(@baseline_dir)
|
53
|
+
image = diff.is_a?(String) ? Monet::Image.new(diff) : diff.image
|
54
54
|
|
55
|
-
|
56
|
-
|
55
|
+
puts "baselining #{image.path}"
|
56
|
+
image = rebase(image)
|
57
57
|
|
58
|
-
|
58
|
+
# delete diff image
|
59
|
+
discard @router.diff_dir(image.name)
|
59
60
|
|
60
|
-
@router.
|
61
|
+
image.thumbnail!(@router.thumbnail_dir) if @config.thumbnail?
|
62
|
+
image.path
|
61
63
|
end
|
62
64
|
|
63
65
|
private
|
64
|
-
|
65
|
-
|
66
|
+
# returns a new image for the moved image
|
67
|
+
def rebase(image)
|
68
|
+
new_path = @router.baseline_dir(image.name)
|
69
|
+
|
70
|
+
create_path_for_file(new_path)
|
71
|
+
FileUtils.move(image.path, new_path)
|
72
|
+
|
73
|
+
Monet::Image.new(new_path)
|
74
|
+
end
|
75
|
+
|
76
|
+
def create_path_for_file(file)
|
77
|
+
path = File.dirname(file)
|
78
|
+
FileUtils.mkpath path unless Dir.exists? path
|
66
79
|
end
|
67
80
|
end
|
68
81
|
end
|
data/lib/monet/capture.rb
CHANGED
@@ -4,8 +4,8 @@ require "capybara"
|
|
4
4
|
require 'capybara/poltergeist'
|
5
5
|
require "capybara/dsl"
|
6
6
|
|
7
|
-
require 'monet/
|
8
|
-
require 'monet/
|
7
|
+
require 'monet/router'
|
8
|
+
require 'monet/image'
|
9
9
|
|
10
10
|
module Monet
|
11
11
|
class Capture
|
@@ -14,45 +14,46 @@ module Monet
|
|
14
14
|
MAX_HEIGHT = 10000
|
15
15
|
|
16
16
|
def initialize(config)
|
17
|
-
@config =
|
18
|
-
@router = Monet::
|
17
|
+
@config = config
|
18
|
+
@router = Monet::Router.new config
|
19
19
|
|
20
20
|
Capybara.default_driver = @config.driver
|
21
21
|
end
|
22
22
|
|
23
23
|
def capture_all
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
def capture(path)
|
30
|
-
visit @router.build_url(path)
|
31
|
-
|
32
|
-
@config.dimensions.each do |width|
|
33
|
-
file_path = @router.route_url_path(path, width)
|
24
|
+
images = []
|
25
|
+
@router.capture_routes.map do |url, paths|
|
26
|
+
visit_once url
|
34
27
|
|
35
|
-
|
36
|
-
|
28
|
+
paths.each do |path|
|
29
|
+
image = Monet::Image.new path
|
30
|
+
capture(url, image)
|
37
31
|
|
38
|
-
|
32
|
+
images << image
|
33
|
+
end
|
39
34
|
end
|
35
|
+
|
36
|
+
images
|
40
37
|
end
|
41
38
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
def capture(url, image_or_save_path)
|
40
|
+
if image_or_save_path.is_a? String
|
41
|
+
image = Monet::Image.new image_or_save_path
|
42
|
+
else
|
43
|
+
image = image_or_save_path
|
44
|
+
end
|
47
45
|
|
48
|
-
|
46
|
+
visit_once url
|
49
47
|
|
50
|
-
|
51
|
-
|
48
|
+
page.driver.resize(image.width, MAX_HEIGHT)
|
49
|
+
page.driver.render(image.path, full: true)
|
52
50
|
|
53
|
-
|
51
|
+
image.thumbnail!(@router.thumbnail_dir) if @config.thumbnail?
|
52
|
+
end
|
54
53
|
|
55
|
-
|
54
|
+
private
|
55
|
+
def visit_once(url)
|
56
|
+
visit url unless current_url == url
|
56
57
|
end
|
57
58
|
end
|
58
59
|
end
|
data/lib/monet/capture_map.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
require 'spidr'
|
2
2
|
require 'monet/url_helpers'
|
3
|
+
require 'forwardable'
|
3
4
|
|
4
5
|
module Monet
|
5
6
|
class CaptureMap
|
6
7
|
extend Forwardable
|
7
8
|
|
8
9
|
class PathCollection
|
10
|
+
extend Forwardable
|
11
|
+
|
9
12
|
include URLHelpers
|
10
13
|
attr_reader :paths, :root_url
|
11
14
|
|
@@ -25,6 +28,8 @@ module Monet
|
|
25
28
|
def normalized_path(path)
|
26
29
|
path.chomp "/"
|
27
30
|
end
|
31
|
+
|
32
|
+
def_delegators :paths, :size, :length, :count
|
28
33
|
end
|
29
34
|
|
30
35
|
class PathSpider < PathCollection
|
@@ -32,7 +37,10 @@ module Monet
|
|
32
37
|
SKIP_PATHS = [/\?.*/]
|
33
38
|
|
34
39
|
def paths
|
35
|
-
@paths
|
40
|
+
return @paths unless @paths.empty?
|
41
|
+
|
42
|
+
normalize Spidr.site(@root_url, ignore_links: ignores)
|
43
|
+
@paths.uniq!
|
36
44
|
end
|
37
45
|
|
38
46
|
def ignores
|
@@ -41,7 +49,7 @@ module Monet
|
|
41
49
|
|
42
50
|
private
|
43
51
|
def normalize(spider_results)
|
44
|
-
spider_results.history.
|
52
|
+
spider_results.history.each {|path| add(path.path) }
|
45
53
|
end
|
46
54
|
end
|
47
55
|
|
@@ -54,7 +62,7 @@ module Monet
|
|
54
62
|
yield(@path_helper) if block_given?
|
55
63
|
end
|
56
64
|
|
57
|
-
def_delegators :@path_helper, :paths, :paths=, :add, :root_url
|
65
|
+
def_delegators :@path_helper, :paths, :paths=, :add, :root_url, :size, :count, :length
|
58
66
|
|
59
67
|
def type_mapper
|
60
68
|
case @type
|
data/lib/monet/changeset.rb
CHANGED
data/lib/monet/config.rb
CHANGED
@@ -21,29 +21,29 @@ module Monet
|
|
21
21
|
|
22
22
|
attr_accessor *DEFAULT_OPTIONS.keys
|
23
23
|
|
24
|
+
# configure via options
|
24
25
|
def initialize(opts={})
|
25
26
|
DEFAULT_OPTIONS.each do |opt, default|
|
26
27
|
send "#{opt}=", opts[opt] || default
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
31
|
+
# configure via block
|
30
32
|
def self.config(&block)
|
31
33
|
cfg = new
|
32
|
-
|
34
|
+
yield cfg if block_given?
|
35
|
+
|
33
36
|
cfg
|
34
37
|
end
|
35
38
|
|
39
|
+
# configure via YAML
|
36
40
|
def self.load(path="./config.yaml")
|
37
|
-
|
38
|
-
new(
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.build_config(opts)
|
42
|
-
(opts.is_a? Monet::Config) ? opts : new(opts)
|
41
|
+
opts = YAML::load(File.open(path))
|
42
|
+
new(opts)
|
43
43
|
end
|
44
44
|
|
45
45
|
def base_url=(url)
|
46
|
-
@base_url
|
46
|
+
@base_url = parse_uri(url) unless url.nil?
|
47
47
|
end
|
48
48
|
|
49
49
|
def base_url
|
@@ -51,6 +51,12 @@ module Monet
|
|
51
51
|
@base_url
|
52
52
|
end
|
53
53
|
|
54
|
+
def site
|
55
|
+
parse_uri(base_url).host
|
56
|
+
end
|
57
|
+
alias_method :host, :site
|
58
|
+
alias_method :root_dir, :site
|
59
|
+
|
54
60
|
def thumbnail?
|
55
61
|
!!thumbnail
|
56
62
|
end
|
@@ -68,13 +74,14 @@ module Monet
|
|
68
74
|
end
|
69
75
|
|
70
76
|
def map=(paths)
|
71
|
-
map
|
77
|
+
@map = nil
|
78
|
+
return @map if paths.nil?
|
79
|
+
paths == :spider ? map(paths) : (map.paths = paths)
|
72
80
|
end
|
73
81
|
|
74
82
|
def map(type=:explicit, &block)
|
75
83
|
@map ||= CaptureMap.new(base_url, type)
|
76
|
-
|
77
|
-
block.call(@map) if block_given? && type == :explicit
|
84
|
+
yield @map if block_given?
|
78
85
|
|
79
86
|
@map
|
80
87
|
end
|
data/lib/monet/image.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'chunky_png'
|
2
|
+
require 'monet/config'
|
3
|
+
require 'monet/url_helpers'
|
4
|
+
|
5
|
+
module Monet
|
6
|
+
class Image
|
7
|
+
include URLHelpers
|
8
|
+
|
9
|
+
attr_reader :path
|
10
|
+
|
11
|
+
def initialize(path)
|
12
|
+
@path = File.expand_path path
|
13
|
+
end
|
14
|
+
|
15
|
+
def is_diff?
|
16
|
+
name.include? "-diff"
|
17
|
+
end
|
18
|
+
|
19
|
+
def diff_path
|
20
|
+
@path.gsub(".png", "-diff.png")
|
21
|
+
end
|
22
|
+
|
23
|
+
def flagged?
|
24
|
+
File.exists? diff_path
|
25
|
+
end
|
26
|
+
|
27
|
+
def width
|
28
|
+
@width ||= File.basename(@path, ".png").split("-").last.to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
def name
|
32
|
+
@name ||= File.basename @path
|
33
|
+
end
|
34
|
+
|
35
|
+
def basename
|
36
|
+
@path.split(File::SEPARATOR)[-2..-1].join(File::SEPARATOR)
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_image
|
40
|
+
ChunkyPNG::Image.from_file(@path)
|
41
|
+
end
|
42
|
+
|
43
|
+
def root_dir
|
44
|
+
File.dirname @path
|
45
|
+
end
|
46
|
+
|
47
|
+
def thumbnail!(save_to=nil)
|
48
|
+
img = to_image
|
49
|
+
short_edge = [img.width, img.height].min
|
50
|
+
|
51
|
+
cropped = img.crop(0, 0, short_edge, short_edge)
|
52
|
+
resized = cropped.resize(200, 200)
|
53
|
+
|
54
|
+
if save_to.nil?
|
55
|
+
save_to = @path.gsub(".png", "-thumb.png")
|
56
|
+
else
|
57
|
+
save_to = File.join save_to, File.basename(@path)
|
58
|
+
end
|
59
|
+
|
60
|
+
save_dir = File.dirname(save_to)
|
61
|
+
FileUtils.mkdir_p save_dir unless Dir.exists?(save_dir)
|
62
|
+
|
63
|
+
resized.save save_to
|
64
|
+
save_to
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/monet/router.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
module Monet
|
2
|
+
class Router
|
3
|
+
include URLHelpers
|
4
|
+
TYPES = [
|
5
|
+
:baseline,
|
6
|
+
:capture,
|
7
|
+
:thumbnail
|
8
|
+
]
|
9
|
+
|
10
|
+
def initialize(config)
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
TYPES.each do |type|
|
15
|
+
define_method "#{type}_dir" do |filename=""|
|
16
|
+
File.join(@config.send("#{type}_dir"), @config.site, filename).chomp("/")
|
17
|
+
end
|
18
|
+
|
19
|
+
define_method "#{type}_url" do |filename|
|
20
|
+
type_dir = @config.send "#{type}_dir"
|
21
|
+
image_url(type_dir, filename)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def original_url(path)
|
26
|
+
url = path.split("/").last
|
27
|
+
path = url.split('|')[1..-1].join("/").gsub(/-\d+\.png/, "")
|
28
|
+
|
29
|
+
"#{@config.base_url}/#{path}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def diff_dir(filename="")
|
33
|
+
filename = filename.gsub(".png", "-diff.png") unless filename.empty?
|
34
|
+
File.join(@config.baseline_dir, @config.site, filename).chomp("/")
|
35
|
+
end
|
36
|
+
|
37
|
+
def diff_url(path)
|
38
|
+
diff = basename diff_dir(path)
|
39
|
+
image_url(@config.baseline_dir, diff)
|
40
|
+
end
|
41
|
+
|
42
|
+
def capture_routes
|
43
|
+
urls = {}
|
44
|
+
@config.map.paths.each do |path|
|
45
|
+
url = "#{@config.base_url}#{path}".chomp("/")
|
46
|
+
@config.dimensions.each do |width|
|
47
|
+
urls[url] ||= []
|
48
|
+
urls[url] << url_to_filepath(url, width)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
urls
|
53
|
+
end
|
54
|
+
|
55
|
+
def url_to_filepath(url, width="*")
|
56
|
+
uri = parse_uri(url)
|
57
|
+
name = File.join @config.site, "#{@config.site}#{uri.path.gsub(/\//, '|')}"
|
58
|
+
File.join @config.capture_dir, "#{name}-#{width}.png"
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def basename(path)
|
63
|
+
File.basename path
|
64
|
+
end
|
65
|
+
|
66
|
+
def image_url(type_dir, name)
|
67
|
+
relative_path = Pathname.new(type_dir).relative_path_from(Pathname.new(File.join(type_dir, "..")))
|
68
|
+
"/#{relative_path}/#{@config.root_dir}/#{name}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/monet/tasks.rb
CHANGED
@@ -12,27 +12,30 @@ end
|
|
12
12
|
namespace :monet do
|
13
13
|
desc "clean out the baseline directory"
|
14
14
|
task :clean, :path do |t, args|
|
15
|
-
|
15
|
+
config = load_config(args)
|
16
|
+
Dir.glob(File.join(config.baseline_dir, "**", "*.png")).each do |img|
|
17
|
+
File.delete img
|
18
|
+
end
|
16
19
|
end
|
17
20
|
|
18
21
|
desc "Runs the site and grabs baselines"
|
19
22
|
task :baseline => [:clean, :run] do
|
20
23
|
end
|
21
24
|
|
22
|
-
|
23
25
|
namespace :thumbnail do
|
24
26
|
desc "Thumbnail all baseline images"
|
25
|
-
task :baseline do
|
27
|
+
task :baseline, :path do |t, args|
|
26
28
|
config = load_config(args)
|
27
29
|
capture = Monet::Capture.new config
|
28
30
|
|
29
31
|
images_from_dir(config.baseline_dir).each do |image|
|
30
|
-
|
32
|
+
Monet::Image.new(image).thumbnail! config.thumbnail_dir
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
34
36
|
desc "Thumnail all captured images"
|
35
|
-
task :captures do
|
37
|
+
task :captures, :path do |t, args|
|
38
|
+
config = load_config(args)
|
36
39
|
capture = Monet::Capture.new config
|
37
40
|
|
38
41
|
images_from_dir(config.capture_dir).each do |image|
|
@@ -44,7 +47,7 @@ namespace :monet do
|
|
44
47
|
desc "Run the baseline comparison"
|
45
48
|
task :run, :path do |t, args|
|
46
49
|
config = load_config(args)
|
47
|
-
Monet.
|
48
|
-
Monet.
|
50
|
+
Monet::Capture.new(config).capture_all
|
51
|
+
Monet::BaselineControl.new(config).run
|
49
52
|
end
|
50
53
|
end
|
data/lib/monet/version.rb
CHANGED
data/lib/monet.rb
CHANGED
@@ -1,34 +1,9 @@
|
|
1
1
|
require "monet/version"
|
2
2
|
require 'monet/config'
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require 'monet/capture'
|
4
|
+
require 'monet/baseline_control'
|
5
|
+
require 'monet/router'
|
6
|
+
require 'monet/image'
|
6
7
|
|
7
8
|
module Monet
|
8
|
-
class << self
|
9
|
-
def clean(opts)
|
10
|
-
config = load_config(opts)
|
11
|
-
Dir.glob(File.join(config.baseline_dir, "**", "*.png")).each do |img|
|
12
|
-
File.delete img
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def capture(opts)
|
17
|
-
agent = Monet::Capture.new(load_config(opts))
|
18
|
-
agent.capture_all
|
19
|
-
end
|
20
|
-
|
21
|
-
def compare(opts)
|
22
|
-
control = Monet::BaselineControl.new(opts)
|
23
|
-
control.run
|
24
|
-
end
|
25
|
-
|
26
|
-
def config(&block)
|
27
|
-
Monet::Config.config block
|
28
|
-
end
|
29
|
-
|
30
|
-
def load_config(options)
|
31
|
-
Monet::Config.build_config(options)
|
32
|
-
end
|
33
|
-
end
|
34
9
|
end
|
data/spec/capture_map_spec.rb
CHANGED
@@ -59,57 +59,12 @@ describe Monet::CaptureMap do
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
context "spider mapper", vcr: { cassette_name: "spider", record: :new_episodes } do
|
63
|
-
Given(:map) { Monet::CaptureMap.new("http://
|
62
|
+
context "spider mapper", vcr: { cassette_name: "spider-map", record: :new_episodes } do
|
63
|
+
Given(:map) { Monet::CaptureMap.new("http://staging.lance.com", :spider) }
|
64
64
|
When(:paths) { map.paths }
|
65
|
-
Then { paths.should ==
|
66
|
-
|
67
|
-
|
68
|
-
"http://www.spider.io/viewability/",
|
69
|
-
"http://www.spider.io/press/",
|
70
|
-
"http://www.spider.io/team/",
|
71
|
-
"http://www.spider.io/blog/",
|
72
|
-
"http://www.spider.io/",
|
73
|
-
"http://www.spider.io/blog/2013/03/chameleon-botnet/",
|
74
|
-
"http://www.spider.io/blog/2013/12/cyber-criminals-defraud-display-advertisers-with-tdss/",
|
75
|
-
"http://www.spider.io/zeus",
|
76
|
-
"http://www.spider.io/blog/2013/11/how-to-defraud-display-advertisers-with-zeus/",
|
77
|
-
"http://www.spider.io/blog/2013/05/a-botnet-primer-for-display-advertisers/",
|
78
|
-
"http://www.spider.io/blog/2013/09/display-advertisers-funding-cybercriminals-since-2011/",
|
79
|
-
"http://www.spider.io/blog/2013/09/securing-the-legitimacy-of-display-ad-inventory/",
|
80
|
-
"http://www.spider.io/blog/2013/04/display-advertising-fraud-is-a-sell-side-problem/",
|
81
|
-
"http://www.spider.io/blog/2012/12/internet-explorer-data-leakage/",
|
82
|
-
"http://www.spider.io/blog/2013/08/sambreel-is-still-injecting-ads-video-advertisers-beware/",
|
83
|
-
"http://www.spider.io/blog/page/2/",
|
84
|
-
"http://www.spider.io/blog/2011/10/the-problem-with-client-side-analytics/",
|
85
|
-
"http://www.spider.io/blog/2012/12/responsible-disclosure/",
|
86
|
-
"http://www.spider.io/blog/2013/05/spider-io-granted-mrc-accreditation-for-viewable-impression-measurement/",
|
87
|
-
"http://www.spider.io/blog/2013/04/at-least-two-percent-of-monitored-display-ad-exchange-inventory-is-hidden/",
|
88
|
-
"http://www.spider.io/blog/2013/03/who-is-behind-the-chameleon-botnet/",
|
89
|
-
"http://www.spider.io/blog/page/3/",
|
90
|
-
"http://www.spider.io/blog/2013/02/which-display-ad-exchange-sells-the-highest-quality-inventory/",
|
91
|
-
"http://www.spider.io/blog/2012/12/there-are-two-ways-to-measure-ad-viewability-there-is-only-one-right-way/",
|
92
|
-
"http://www.spider.io/blog/page/4/",
|
93
|
-
"http://www.spider.io/blog/2012/12/review-of-iab-safeframe-1-0/",
|
94
|
-
"http://www.spider.io/blog/2012/10/qa-about-ad-viewability/",
|
95
|
-
"http://www.spider.io/blog/2012/10/the-first-technology-to-measure-the-viewability-of-iframed-ads-across-all-major-browsers-press-release/",
|
96
|
-
"http://www.spider.io/vSta98h",
|
97
|
-
"http://www.spider.io/blog/2012/07/join-us-for-a-tipple-at-spider-towers/",
|
98
|
-
"http://www.spider.io/blog/2012/07/startups-acquiring-startups-for-equity/",
|
99
|
-
"http://www.spider.io/blog/page/5/",
|
100
|
-
"http://www.spider.io/visibility-demo-screencast/",
|
101
|
-
"http://www.spider.io/blog/2012/07/whats-in-an-ip-address/",
|
102
|
-
"http://www.spider.io/blog/2011/12/physical-hack-day/",
|
103
|
-
"http://www.spider.io/blog/2011/11/our-first-hack-day/",
|
104
|
-
"http://www.spider.io/careers/",
|
105
|
-
"http://www.spider.io/blog/2011/10/extreme-architecting/",
|
106
|
-
"http://www.spider.io/blog/2011/09/how-to-catch-a-bot/",
|
107
|
-
"http://www.spider.io/blog/page/6/",
|
108
|
-
"http://www.spider.io/blog/2011/10/testing-javascript-with-mturk/",
|
109
|
-
"http://www.spider.io/blog/2011/10/demonstration-screencast-verifying-that-display-ads-are-visible-from-within-iframes/",
|
110
|
-
"http://www.spider.io/blog/2011/10/calling-out-to-researchersacademics/",
|
111
|
-
"http://www.spider.io/blog/page/7/"
|
112
|
-
]}
|
65
|
+
Then { paths.size.should == 64 }
|
66
|
+
And { paths.first.end_with?("/").should be false }
|
67
|
+
And { paths.first.start_with?("http://").should be_false }
|
113
68
|
And { paths.any? {|p| p.end_with? "css" }.should be_false }
|
114
69
|
end
|
115
70
|
end
|