Narnach-blocklist 0.1.1
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/MIT-LICENSE +20 -0
- data/README.rdoc +58 -0
- data/Rakefile +49 -0
- data/bin/blocklist +3 -0
- data/blocklist.gemspec +32 -0
- data/lib/blocklist.rb +111 -0
- data/lib/blocklist/cli.rb +102 -0
- data/spec/blocklist/cli_spec.rb +56 -0
- data/spec/blocklist_spec.rb +100 -0
- data/spec/spec_helper.rb +9 -0
- metadata +68 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Wes Oldenbeuving
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
= Blocklist
|
2
|
+
Blocklist manages /etc/hosts with the goal of routing distracting websites to localhost. It also works well as an ad blocker.
|
3
|
+
|
4
|
+
== Usage
|
5
|
+
|
6
|
+
You'll need read/write access to /etc/hosts to make this work. It might also be a good idea to keep a backup of /etc/hosts, just in case. Keeping it in a git repo works for me. YMMV.
|
7
|
+
|
8
|
+
Blocklist makes a couple of assumtions about how /etc/hosts is set up. Here's a typical dummy file:
|
9
|
+
# localhost
|
10
|
+
127.0.0.1 localhost
|
11
|
+
255.255.255.255 broadcasthost
|
12
|
+
::1 localhost
|
13
|
+
|
14
|
+
# disabled
|
15
|
+
# 127.0.0.1 example.org
|
16
|
+
|
17
|
+
The above shows that there are blocks of lines, separated by one or more blank lines. Each of these blocks starts with a single comment that names it. Commented-out blocks are prefixed with "# "; hash-space.
|
18
|
+
|
19
|
+
=== List all blocks
|
20
|
+
$ blocklist list
|
21
|
+
localhost
|
22
|
+
ads
|
23
|
+
disabled
|
24
|
+
|
25
|
+
=== Toggle a block to be commented-out or not
|
26
|
+
$ blocklist toggle disabled
|
27
|
+
# localhost
|
28
|
+
127.0.0.1 localhost
|
29
|
+
255.255.255.255 broadcasthost
|
30
|
+
::1 localhost
|
31
|
+
|
32
|
+
# disabled
|
33
|
+
127.0.0.1 example.org
|
34
|
+
|
35
|
+
=== Add a domain
|
36
|
+
Add a domain to a new or existing block. It automatically adds the subdomain you specified, but it also adds the full domain and the www. subdomain.
|
37
|
+
There is support for domains on a TLD that always have a subdomain. The only one that is added out of the box is .co.uk. When you need more, please submit a patch.
|
38
|
+
|
39
|
+
$ blocklist add someblock news.example.org
|
40
|
+
# localhost
|
41
|
+
127.0.0.1 localhost
|
42
|
+
255.255.255.255 broadcasthost
|
43
|
+
::1 localhost
|
44
|
+
|
45
|
+
# disabled
|
46
|
+
127.0.0.1 example.org
|
47
|
+
|
48
|
+
# someblock
|
49
|
+
127.0.0.1 news.example.org example.org www.example.org
|
50
|
+
|
51
|
+
== Development
|
52
|
+
|
53
|
+
You'll need rspec and fakefs to get the specs running.
|
54
|
+
|
55
|
+
Patches are always welcome. Please add tests or specs and create a github issue or send a pull request.
|
56
|
+
|
57
|
+
== Authors
|
58
|
+
* Wes 'Narnach' Oldenbeuving <http://github.com/Narnach>
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require "rake"
|
2
|
+
require "rake/clean"
|
3
|
+
require "rake/gempackagetask"
|
4
|
+
require 'rubygems'
|
5
|
+
|
6
|
+
################################################################################
|
7
|
+
### Gem
|
8
|
+
################################################################################
|
9
|
+
|
10
|
+
begin
|
11
|
+
# Parse gemspec using the github safety level.
|
12
|
+
file = Dir['*.gemspec'].first
|
13
|
+
data = File.read(file)
|
14
|
+
spec = nil
|
15
|
+
# FIXME: Lowered SAFE from 3 to 2 to work with Ruby 1.9 due to rubygems
|
16
|
+
# performing a require internally
|
17
|
+
Thread.new { spec = eval("$SAFE = 2\n%s" % data)}.join
|
18
|
+
|
19
|
+
# Create the gem tasks
|
20
|
+
Rake::GemPackageTask.new(spec) do |package|
|
21
|
+
package.gem_spec = spec
|
22
|
+
end
|
23
|
+
rescue Exception => e
|
24
|
+
printf "WARNING: Error caught (%s): %s\n%s", e.class.name, e.message, e.backtrace[0...5].map {|l| ' %s' % l}.join("\n")
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Package and install the gem for the current version'
|
28
|
+
task :install => :gem do
|
29
|
+
system "sudo gem install -l pkg/%s-%s.gem" % [spec.name, spec.version]
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'Show files missing from gemspec'
|
33
|
+
task :diff do
|
34
|
+
files = %w[
|
35
|
+
Rakefile
|
36
|
+
*README*
|
37
|
+
*LICENSE*
|
38
|
+
*.gemspec
|
39
|
+
bin/*
|
40
|
+
lib/**/*
|
41
|
+
spec/**/*
|
42
|
+
].map {|pattern| Dir.glob(pattern)}.flatten.select{|f| File.file?(f)}
|
43
|
+
missing_files = files - spec.files
|
44
|
+
extra_files = spec.files - files
|
45
|
+
puts "Missing files:"
|
46
|
+
puts missing_files.join(" ")
|
47
|
+
puts "Extra files:"
|
48
|
+
puts extra_files.join(" ")
|
49
|
+
end
|
data/bin/blocklist
ADDED
data/blocklist.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
# Project
|
3
|
+
s.name = 'blocklist'
|
4
|
+
s.summary = "Blocklist manages /etc/hosts"
|
5
|
+
s.description = "Blocklist manages /etc/hosts with the goal of routing distracting websites to localhost. It also works well as an ad blocker."
|
6
|
+
s.version = '0.1.1'
|
7
|
+
s.date = '2009-09-15'
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Wes Oldenbeuving"]
|
10
|
+
s.email = "narnach@gmail.com"
|
11
|
+
s.homepage = "http://www.github.com/Narnach/blocklist"
|
12
|
+
|
13
|
+
# Files
|
14
|
+
root_files = %w[MIT-LICENSE README.rdoc Rakefile blocklist.gemspec]
|
15
|
+
bin_files = %w[blocklist]
|
16
|
+
lib_files = %w[blocklist blocklist/cli]
|
17
|
+
spec_files = %w[blocklist blocklist/cli]
|
18
|
+
other_files = %w[spec/spec_helper.rb]
|
19
|
+
s.bindir = "bin"
|
20
|
+
s.require_path = "lib"
|
21
|
+
s.executables = bin_files
|
22
|
+
s.test_files = spec_files.map {|f| 'spec/%s_spec.rb' % f}
|
23
|
+
s.files = root_files + s.test_files + other_files + bin_files.map {|f| 'bin/%s' % f} + lib_files.map {|f| 'lib/%s.rb' % f}
|
24
|
+
|
25
|
+
# rdoc
|
26
|
+
s.has_rdoc = true
|
27
|
+
s.extra_rdoc_files = %w[ README.rdoc MIT-LICENSE]
|
28
|
+
s.rdoc_options << '--inline-source' << '--line-numbers' << '--main' << 'README.rdoc'
|
29
|
+
|
30
|
+
# Requirements
|
31
|
+
s.required_ruby_version = ">= 1.8.0"
|
32
|
+
end
|
data/lib/blocklist.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
class Blocklist
|
2
|
+
attr_accessor :blocks
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
self.blocks = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse(content)
|
9
|
+
block = Block.new
|
10
|
+
content.each_line do |line|
|
11
|
+
parsed_line = Line.parse(line)
|
12
|
+
case parsed_line
|
13
|
+
when nil
|
14
|
+
self.blocks << block
|
15
|
+
block = Block.new
|
16
|
+
when String
|
17
|
+
block.name ||= parsed_line
|
18
|
+
when Line
|
19
|
+
block.lines << parsed_line
|
20
|
+
else
|
21
|
+
raise "Unexpected line: #{line}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
if block.name or block.lines.size > 0
|
25
|
+
self.blocks << block
|
26
|
+
end
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def block(name)
|
31
|
+
blocks.find {|block| block.name == name}
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
blocks.join("\n\n")
|
36
|
+
end
|
37
|
+
|
38
|
+
class Block
|
39
|
+
attr_accessor :name, :lines
|
40
|
+
|
41
|
+
def initialize(name=nil, *lines)
|
42
|
+
self.name = name
|
43
|
+
self.lines = lines
|
44
|
+
end
|
45
|
+
|
46
|
+
def ==(other)
|
47
|
+
return false unless other.class == self.class
|
48
|
+
return false unless other.name == self.name
|
49
|
+
return false unless other.lines == self.lines
|
50
|
+
true
|
51
|
+
end
|
52
|
+
|
53
|
+
def toggle_comments
|
54
|
+
lines.each {|line| line.toggle_comment}
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_s
|
58
|
+
"# #{name}\n" + lines.join("\n")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Line
|
63
|
+
COMMENT_PREFIX = /\A#+\s+/
|
64
|
+
IPV4 = /\A\d{1,3}(\.\d{1,3}){3}/
|
65
|
+
# Took this huge regexp from http://vernon.mauery.com/content/projects/linux/ipv6_regex
|
66
|
+
IPV6 = /(\A([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,6}\Z)|(\A([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}\Z)|(\A([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}\Z)|(\A([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}\Z)|(\A([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}\Z)|(\A([0-9a-f]{1,4}:){1,6}(:[0-9a-f]{1,4}){1,1}\Z)|(\A(([0-9a-f]{1,4}:){1,7}|:):\Z)|(\A:(:[0-9a-f]{1,4}){1,7}\Z)|(\A((([0-9a-f]{1,4}:){6})(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3})\Z)|(\A(([0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3})\Z)|(\A([0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}\Z)|(\A([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,4}:(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}\Z)|(\A([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,3}:(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}\Z)|(\A([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,2}:(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}\Z)|(\A([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,1}:(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}\Z)|(\A(([0-9a-f]{1,4}:){1,5}|:):(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}\Z)|(\A:(:[0-9a-f]{1,4}){1,5}:(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}\Z)/
|
67
|
+
|
68
|
+
attr_accessor :ip, :domains, :commented
|
69
|
+
|
70
|
+
def initialize(ip, *domains)
|
71
|
+
self.ip = ip
|
72
|
+
self.domains = domains
|
73
|
+
self.commented = false
|
74
|
+
end
|
75
|
+
|
76
|
+
def ==(other)
|
77
|
+
return false unless other.class == self.class
|
78
|
+
return false unless other.ip == self.ip
|
79
|
+
return false unless other.domains == self.domains
|
80
|
+
true
|
81
|
+
end
|
82
|
+
|
83
|
+
def toggle_comment
|
84
|
+
self.commented = !commented
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_s
|
88
|
+
prefix = commented ? "# " : ""
|
89
|
+
"%s%s%s%s" % [prefix, ip, " " * (16 - ip.size), domains.join(" ")]
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.parse(line)
|
93
|
+
stripped_line = line.strip
|
94
|
+
return nil if stripped_line == ''
|
95
|
+
return Line.new(*stripped_line.split(" ")) unless stripped_line =~ COMMENT_PREFIX
|
96
|
+
uncommented_line = stripped_line.gsub(COMMENT_PREFIX, '')
|
97
|
+
split_line = uncommented_line.split(" ")
|
98
|
+
if split_line.first =~ IPV4
|
99
|
+
parsed_line = Line.new(*split_line)
|
100
|
+
parsed_line.commented = true
|
101
|
+
parsed_line
|
102
|
+
elsif split_line.first =~ IPV6
|
103
|
+
parsed_line = Line.new(*split_line)
|
104
|
+
parsed_line.commented = true
|
105
|
+
parsed_line
|
106
|
+
else # comment or title
|
107
|
+
uncommented_line
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'blocklist'
|
2
|
+
|
3
|
+
class Blocklist
|
4
|
+
class Cli
|
5
|
+
COMMANDS = %w[add list toggle help]
|
6
|
+
def initialize(argv)
|
7
|
+
@argv = argv
|
8
|
+
@bl = Blocklist.new
|
9
|
+
@bl.parse(File.read('/etc/hosts'))
|
10
|
+
@dry_run = !@argv.delete('-d').nil?
|
11
|
+
@quiet = !@argv.delete('-q').nil?
|
12
|
+
@command = @argv.shift || 'help'
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
if COMMANDS.include? @command
|
17
|
+
self.send(@command)
|
18
|
+
else
|
19
|
+
help "Command unknown: '#{@command}'"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def list
|
26
|
+
puts @bl.blocks.map {|block| block.name}.join("\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
def add
|
30
|
+
block_name = @argv.shift
|
31
|
+
block = @bl.block(block_name) || Blocklist::Block.new(block_name)
|
32
|
+
|
33
|
+
domains = block.lines.map {|line| line.domains}.flatten
|
34
|
+
saved_domains = @argv.map do |domain|
|
35
|
+
dom_segments = domain.split(".")
|
36
|
+
tld_size = 1
|
37
|
+
tld_size = 2 if %w[uk].include? dom_segments.last
|
38
|
+
tld = dom_segments[-tld_size..-1].join(".")
|
39
|
+
dom_no_tld = dom_segments[0...-tld_size]
|
40
|
+
domain_base = dom_no_tld.last
|
41
|
+
subdomain = dom_no_tld.size == 1 ? nil : dom_no_tld[0...-1].join(".")
|
42
|
+
new_domains = [nil, 'www', subdomain].uniq.map {|sub| [sub, domain_base, tld].compact.join(".")} - domains
|
43
|
+
if new_domains.size > 0
|
44
|
+
block.lines << Blocklist::Line.new('127.0.0.1', *new_domains)
|
45
|
+
domains.concat(new_domains)
|
46
|
+
end
|
47
|
+
new_domains
|
48
|
+
end
|
49
|
+
display_result
|
50
|
+
save if saved_domains.flatten.size > 0
|
51
|
+
end
|
52
|
+
|
53
|
+
def toggle
|
54
|
+
block_name = @argv.shift
|
55
|
+
unless block = @bl.block(block_name)
|
56
|
+
help "Could not toggle non-existing block '#{block_name}'"
|
57
|
+
return
|
58
|
+
end
|
59
|
+
block.toggle_comments
|
60
|
+
display_result
|
61
|
+
save
|
62
|
+
end
|
63
|
+
|
64
|
+
def help(msg=nil)
|
65
|
+
if msg
|
66
|
+
$stderr.puts(msg)
|
67
|
+
$stderr.puts('')
|
68
|
+
end
|
69
|
+
$stderr.puts <<-STR
|
70
|
+
Syntax: #{$0} [flags] <command>
|
71
|
+
|
72
|
+
Flags:
|
73
|
+
-d
|
74
|
+
Perform a dry-run. Does not modify /etc/hosts
|
75
|
+
-q
|
76
|
+
Quiet mode. Minimizes the output to STDOUT
|
77
|
+
|
78
|
+
Commands:
|
79
|
+
add <block name> [domain1] .. [domainN]
|
80
|
+
Add a number of domains to the specified block.
|
81
|
+
Each domain will automatically be added with the www subdomain and without subdomain.
|
82
|
+
Duplicate domains are skipped.
|
83
|
+
list
|
84
|
+
Shows a list of all blocks currently defined
|
85
|
+
toggle <block name>
|
86
|
+
Toggle the comment status of all lines in this block.
|
87
|
+
help
|
88
|
+
Show this page
|
89
|
+
STR
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def display_result
|
95
|
+
puts @bl unless @quiet
|
96
|
+
end
|
97
|
+
|
98
|
+
def save
|
99
|
+
File.open('/etc/hosts','w') {|f| f.puts(@bl.to_s)} unless @dry_run
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[.. spec_helper])
|
2
|
+
require 'blocklist/cli'
|
3
|
+
begin
|
4
|
+
require 'fakefs/safe'
|
5
|
+
rescue LoadError
|
6
|
+
$stderr.puts "!! You need to install fakefs to run the CLI specs.\n!! Look on http://github/defunkt/fakefs or use gemcutter.org."
|
7
|
+
exit 1
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Blocklist::Cli do
|
11
|
+
before(:each) do
|
12
|
+
FakeFS.activate!
|
13
|
+
end
|
14
|
+
|
15
|
+
after(:each) do
|
16
|
+
FakeFS.deactivate!
|
17
|
+
end
|
18
|
+
|
19
|
+
def fake_hosts(content='')
|
20
|
+
File.open('/etc/hosts','w') {|f| f.puts content}
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should display help when no command is given' do
|
24
|
+
fake_hosts
|
25
|
+
cli = Blocklist::Cli.new([])
|
26
|
+
cli.should_receive(:help)
|
27
|
+
cli.run
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'list' do
|
31
|
+
it 'should show all blocks in /etc/hosts' do
|
32
|
+
fake_hosts <<-STR
|
33
|
+
# localhost
|
34
|
+
|
35
|
+
# blocked
|
36
|
+
STR
|
37
|
+
cli = Blocklist::Cli.new(%w[list])
|
38
|
+
cli.should_receive(:puts).with("localhost\nblocked")
|
39
|
+
cli.run
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'add' do
|
44
|
+
it "should add a domain and its www-subdomain to a block's lines" do
|
45
|
+
fake_hosts <<-STR
|
46
|
+
# localhost
|
47
|
+
STR
|
48
|
+
cli = Blocklist::Cli.new(%w[add localhost example.org])
|
49
|
+
cli.run
|
50
|
+
File.read('/etc/hosts').should == <<-STR
|
51
|
+
# localhost
|
52
|
+
127.0.0.1 example.org www.example.org
|
53
|
+
STR
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
2
|
+
require 'blocklist'
|
3
|
+
|
4
|
+
describe Blocklist do
|
5
|
+
describe '#parse' do
|
6
|
+
it 'should parse all blocks' do
|
7
|
+
hosts = <<-STR
|
8
|
+
# localhost
|
9
|
+
127.0.0.1 localhost
|
10
|
+
255.255.255.255 broadcasthost
|
11
|
+
|
12
|
+
# blocked
|
13
|
+
127.0.0.1 news.ycombinator.com
|
14
|
+
STR
|
15
|
+
bl = Blocklist.new
|
16
|
+
bl.parse(hosts)
|
17
|
+
bl.blocks.map {|block| block.name}.should == %w[localhost blocked]
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should parse all domains on a line' do
|
21
|
+
hosts = <<-STR
|
22
|
+
# blocked
|
23
|
+
127.0.0.1 news.ycombinator.com ycombinator.com
|
24
|
+
STR
|
25
|
+
bl = Blocklist.new
|
26
|
+
bl.parse(hosts)
|
27
|
+
bl.blocks.first.should == Blocklist::Block.new('blocked',
|
28
|
+
Blocklist::Line.new('127.0.0.1', *%w[news.ycombinator.com ycombinator.com]))
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should handle ipv6 addresses' do
|
32
|
+
hosts = <<-STR.strip
|
33
|
+
# localhost
|
34
|
+
127.0.0.1 localhost
|
35
|
+
::1 localhost
|
36
|
+
STR
|
37
|
+
bl = Blocklist.new
|
38
|
+
bl.parse(hosts)
|
39
|
+
bl.blocks.first.should == Blocklist::Block.new('localhost',
|
40
|
+
Blocklist::Line.new('127.0.0.1', 'localhost'),
|
41
|
+
Blocklist::Line.new('::1', 'localhost'))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#to_s' do
|
46
|
+
it 'should display a Blocklist in the /etc/hosts format' do
|
47
|
+
block1 = Blocklist::Block.new('localhost')
|
48
|
+
block1.lines << Blocklist::Line.new('127.0.0.1', 'localhost')
|
49
|
+
block2 = Blocklist::Block.new('blocked')
|
50
|
+
block2.lines << Blocklist::Line.new('127.0.0.1', 'news.ycombinator.com', 'ycombinator.com')
|
51
|
+
bl = Blocklist.new
|
52
|
+
bl.blocks << block1
|
53
|
+
bl.blocks << block2
|
54
|
+
bl.to_s.should == <<-STR.strip
|
55
|
+
# localhost
|
56
|
+
127.0.0.1 localhost
|
57
|
+
|
58
|
+
# blocked
|
59
|
+
127.0.0.1 news.ycombinator.com ycombinator.com
|
60
|
+
STR
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#block' do
|
65
|
+
it 'should find the first block by name' do
|
66
|
+
bl = Blocklist.new
|
67
|
+
bl.parse(<<-STR.strip)
|
68
|
+
# localhost
|
69
|
+
127.0.0.1 localhost
|
70
|
+
|
71
|
+
# blocked
|
72
|
+
127.0.0.1 news.ycombinator.com ycombinator.com
|
73
|
+
STR
|
74
|
+
bl.block('blocked').lines.first.domains.should == %w[news.ycombinator.com ycombinator.com]
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should return nil if no block can be found' do
|
78
|
+
Blocklist.new.block('nothing').should be_nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe Blocklist::Block do
|
84
|
+
describe '#toggle_comments' do
|
85
|
+
it 'should toggle lines between commented-out and not commented' do
|
86
|
+
hosts = <<-STR.strip
|
87
|
+
# blocked
|
88
|
+
127.0.0.1 news.ycombinator.com ycombinator.com
|
89
|
+
STR
|
90
|
+
bl = Blocklist.new
|
91
|
+
bl.parse(hosts)
|
92
|
+
bl.blocks.first.toggle_comments
|
93
|
+
bl.to_s.should_not == hosts
|
94
|
+
bl2 = Blocklist.new
|
95
|
+
bl2.parse(bl.to_s)
|
96
|
+
bl2.blocks.first.toggle_comments
|
97
|
+
bl2.to_s.should == hosts
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Narnach-blocklist
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Wes Oldenbeuving
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-09-15 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Blocklist manages /etc/hosts with the goal of routing distracting websites to localhost. It also works well as an ad blocker.
|
17
|
+
email: narnach@gmail.com
|
18
|
+
executables:
|
19
|
+
- blocklist
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
- MIT-LICENSE
|
25
|
+
files:
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- blocklist.gemspec
|
30
|
+
- spec/blocklist_spec.rb
|
31
|
+
- spec/blocklist/cli_spec.rb
|
32
|
+
- spec/spec_helper.rb
|
33
|
+
- bin/blocklist
|
34
|
+
- lib/blocklist.rb
|
35
|
+
- lib/blocklist/cli.rb
|
36
|
+
has_rdoc: true
|
37
|
+
homepage: http://www.github.com/Narnach/blocklist
|
38
|
+
licenses:
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options:
|
41
|
+
- --inline-source
|
42
|
+
- --line-numbers
|
43
|
+
- --main
|
44
|
+
- README.rdoc
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: 1.8.0
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.3.5
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: Blocklist manages /etc/hosts
|
66
|
+
test_files:
|
67
|
+
- spec/blocklist_spec.rb
|
68
|
+
- spec/blocklist/cli_spec.rb
|