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 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
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'blocklist/cli'
3
+ Blocklist::Cli.new(ARGV.dup).run
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
@@ -0,0 +1,9 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ $stderr.puts "!! You need to install rspec to run the specs.\n!! sudo gem install rspec"
5
+ exit 1
6
+ end
7
+
8
+ lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
9
+ $LOAD_PATH.unshift(lib_dir)
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