work 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/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ .bundle
3
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in work.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ work (0.1.0)
5
+ sys-uname (>= 0.8.5)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.1.2)
11
+ rspec (2.6.0)
12
+ rspec-core (~> 2.6.0)
13
+ rspec-expectations (~> 2.6.0)
14
+ rspec-mocks (~> 2.6.0)
15
+ rspec-core (2.6.0)
16
+ rspec-expectations (2.6.0)
17
+ diff-lcs (~> 1.1.2)
18
+ rspec-mocks (2.6.0)
19
+ sys-uname (0.8.5)
20
+ yard (0.6.8)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ rspec (>= 2.5.0)
27
+ work!
28
+ yard (>= 0.6.4)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Tim Blair
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.md ADDED
@@ -0,0 +1,40 @@
1
+ # Work
2
+
3
+ Anti-procrastination through `hosts` file hackery.
4
+
5
+
6
+ ## Installation
7
+
8
+ $ gem install work
9
+
10
+
11
+ ## Usage ##
12
+
13
+ $ work setup # => sets up default domain list in ~/.work
14
+ $ work [start] # => disables access to domain list
15
+ $ work stop # => enables access to domain list
16
+
17
+ There is also a `play` alias place which inverses the `work` commands:
18
+
19
+ $ play [start] # => enables access to domain list
20
+ $ play stop # => disables access to domain list
21
+
22
+ You can modify your list of work-only domains in `~/.work`. Just
23
+ use the root domain (`www.` will be added automatically.)
24
+
25
+
26
+ ## Credits
27
+
28
+ Ideas and motivation prompted by:
29
+
30
+ * [get-shit-done](http://github.com/leftnode/get-shit-done)
31
+ * Alex Payne: [My Get-Back-To-Work Hack](http://al3x.net/2009/09/14/my-get-back-to-work-hack.html)
32
+
33
+
34
+ ## Licensing and Attribution
35
+
36
+ Copyright (c)2011 [Tim Blair](http://tim.bla.ir/).
37
+
38
+ Work has been released under the MIT license as detailed in the
39
+ LICENSE file that should be distributed with this library; the source code is
40
+ [freely available](http://github.com/timblair/work).
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ #
5
+ # Rspec
6
+ #
7
+
8
+ require 'rspec/core/rake_task'
9
+ RSpec::Core::RakeTask.new(:spec) do |spec|
10
+ spec.pattern = 'spec/**/*_spec.rb'
11
+ end
12
+
13
+ task :default => [:start, :spec, :stop]
14
+
15
+
16
+ #
17
+ # Yard
18
+ #
19
+
20
+ begin
21
+ require 'yard'
22
+ YARD::Rake::YardocTask.new
23
+ rescue LoadError
24
+ task :yardoc do
25
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
26
+ end
27
+ end
28
+
29
+
30
+ #
31
+ # Misc.
32
+ #
33
+
34
+ desc "Start an irb console with Work pre-loaded."
35
+ task :console do
36
+ exec "irb -r spec/spec_helper"
37
+ end
38
+ task :c => :console
data/bin/play ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ require 'work'
5
+
6
+ # Due to access permissions (i.e. the hosts file isn't usually
7
+ # writable to the current user, we need the ability to re-run
8
+ # this process under the super user.
9
+ def sudome
10
+ if ENV["USER"] != "root"
11
+ # `exec` replaces this process, so no need to `exit` as well.
12
+ exec("sudo #{$0} #{ARGV.join(' ')}")
13
+ end
14
+ end
15
+
16
+ # Find the location of the user's work preferences.
17
+ dotfile = Work::DotFile.locate
18
+
19
+ case ARGV.first
20
+ # We need a list of domains to work with, which is stored in a
21
+ # ~/.work hidden file.
22
+ when 'setup'
23
+ dotfile = Work::DotFile.locate
24
+ if dotfile.exists?
25
+ puts "Work file already exists at #{dotfile.path}"
26
+ else
27
+ dotfile.write(Work::DEFAULT_DOMAINS) if !dotfile.exists?
28
+ puts "Default work domains added to #{dotfile.path}"
29
+ end
30
+
31
+ # Not a setup command, so we'll need the `Teacher`
32
+ else
33
+ # Warn the user if they've not set up a domains list
34
+ if dotfile.read.length == 0
35
+ puts "Domain list is empty. Add work domains to #{dotfile.path}"
36
+ puts "or run `#{$0} setup` to populate with the default list."
37
+ exit
38
+ end
39
+
40
+ # If we can't write to the hosts file, re-run but with `sudo`.
41
+ begin
42
+ p = Work::Teacher.new(dotfile.read, ARGV[1], ARGV[2])
43
+ rescue Work::HostsFileNotWritable
44
+ sudome
45
+ end
46
+
47
+ # Decide if we're beginning or ending work.
48
+ cmd = File.basename($0)
49
+ action = ARGV.first || 'on'
50
+
51
+ if (cmd == 'play' && %{ start on begin }.include?(action)) ||
52
+ (cmd != 'play' && %{ stop off end }.include?(action))
53
+ puts "Out in to the playground, children."
54
+ p.play
55
+ else
56
+ puts "Bums on seats, please."
57
+ p.work
58
+ end
59
+
60
+ # Run the command to reload the machine's DNS cache.
61
+ p.recache!
62
+ end
data/bin/work ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ require 'work'
5
+
6
+ # Due to access permissions (i.e. the hosts file isn't usually
7
+ # writable to the current user, we need the ability to re-run
8
+ # this process under the super user.
9
+ def sudome
10
+ if ENV["USER"] != "root"
11
+ # `exec` replaces this process, so no need to `exit` as well.
12
+ exec("sudo #{$0} #{ARGV.join(' ')}")
13
+ end
14
+ end
15
+
16
+ # Find the location of the user's work preferences.
17
+ dotfile = Work::DotFile.locate
18
+
19
+ case ARGV.first
20
+ # We need a list of domains to work with, which is stored in a
21
+ # ~/.work hidden file.
22
+ when 'setup'
23
+ dotfile = Work::DotFile.locate
24
+ if dotfile.exists?
25
+ puts "Work file already exists at #{dotfile.path}"
26
+ else
27
+ dotfile.write(Work::DEFAULT_DOMAINS) if !dotfile.exists?
28
+ puts "Default work domains added to #{dotfile.path}"
29
+ end
30
+
31
+ # Not a setup command, so we'll need the `Teacher`
32
+ else
33
+ # Warn the user if they've not set up a domains list
34
+ if dotfile.read.length == 0
35
+ puts "Domain list is empty. Add work domains to #{dotfile.path}"
36
+ puts "or run `#{$0} setup` to populate with the default list."
37
+ exit
38
+ end
39
+
40
+ # If we can't write to the hosts file, re-run but with `sudo`.
41
+ begin
42
+ p = Work::Teacher.new(dotfile.read, ARGV[1], ARGV[2])
43
+ rescue Work::HostsFileNotWritable
44
+ sudome
45
+ end
46
+
47
+ # Decide if we're beginning or ending work.
48
+ cmd = File.basename($0)
49
+ action = ARGV.first || 'on'
50
+
51
+ if (cmd == 'play' && %{ start on begin }.include?(action)) ||
52
+ (cmd != 'play' && %{ stop off end }.include?(action))
53
+ puts "Out in to the playground, children."
54
+ p.play
55
+ else
56
+ puts "Bums on seats, please."
57
+ p.work
58
+ end
59
+
60
+ # Run the command to reload the machine's DNS cache.
61
+ p.recache!
62
+ end
@@ -0,0 +1,29 @@
1
+ module Work
2
+ class DotFile
3
+
4
+ attr_accessor :path
5
+
6
+ def self.locate
7
+ @dotfile ||= self.new File.expand_path(File.join('~', '.work'))
8
+ end
9
+
10
+ def initialize(path)
11
+ @path = path
12
+ end
13
+
14
+ def exists?
15
+ File.exists? @path
16
+ end
17
+
18
+ def read
19
+ File.readlines(path).collect { |d| d.strip }.sort rescue []
20
+ end
21
+
22
+ def write(data)
23
+ File.open(path, 'w+') do |f|
24
+ f.write(data.is_a?(Array) ? data.join("\n") : data)
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,70 @@
1
+ require 'digest/md5'
2
+ require 'rubygems'
3
+ require 'sys/uname'
4
+
5
+ module Work
6
+ class Teacher
7
+
8
+ attr_accessor :path, :domains, :ip
9
+
10
+ def initialize(domains, path=nil, ip=nil)
11
+ @domains = domains
12
+ @path = path || "/etc/hosts"
13
+ @ip = ip || "127.0.0.1"
14
+ raise HostsFileNotWritable if !File.writable?(@path)
15
+ end
16
+
17
+ def separator
18
+ @separator ||= "#==#{self.class.name}/#{Digest::MD5.hexdigest(self.class.name + path)}"
19
+ end
20
+
21
+ def msg
22
+ "# Do not modify. Controlled by Work: http://github.com/timblair/work"
23
+ end
24
+
25
+ def work
26
+ File.open(path, 'r+') do |f|
27
+ lines = f.read
28
+ if !lines.match /#{separator}/
29
+ self.class.overwrite_file(f) do
30
+ extra = domains.collect { |d| "#{ip}\t#{d}\twww.#{d}" }
31
+ lines << "\n\n#{separator}\n#{msg}\n#{extra.join("\n")}\n#{separator}"
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def play
38
+ File.open(path, 'r+') do |f|
39
+ lines = f.read
40
+ if lines.match /#{separator}/
41
+ self.class.overwrite_file(f) do
42
+ lines.gsub /([\s\n]*#{separator}.*#{separator})/m, ""
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def recache!
49
+ case Sys::Uname.sysname.downcase
50
+ when 'darwin'
51
+ system 'dscacheutil -flushcache'
52
+ when 'linux'
53
+ system '/etc/init.d/networking restart'
54
+ else
55
+ puts "Warning: unknown system type #{Sys::Uname.sysname.downcase}."
56
+ puts "You'll need to flush your DNS cache yourself..."
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def self.overwrite_file(file, &block)
63
+ text = yield
64
+ file.rewind
65
+ file.write text
66
+ file.truncate text.length
67
+ end
68
+
69
+ end # Class Teacher
70
+ end # Module Work
@@ -0,0 +1,3 @@
1
+ module Work
2
+ VERSION = "0.1.0"
3
+ end
data/lib/work.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'work/version'
2
+ require 'work/teacher'
3
+ require 'work/dotfile'
4
+
5
+ module Work
6
+
7
+ DEFAULT_DOMAINS = %w{
8
+ arstechnica.com boingboing.net cnet.com codinghorror.com crunchgear.com
9
+ daringfireball.net digg.com en.wikipedia.org engadget.com engadgetmobile.com
10
+ facebook.com feedly.com gawker.com gigaom.com gizmodo.com guardian.co.uk
11
+ hacker-newspaper.gilesb.com icombinator.net kottke.org lifehacker.com
12
+ macnn.com macrumors.com mashable.com metafilter.com news.google.com
13
+ news.ycombinator.com nytimes.com radar.oreilly.com readwriteweb.com
14
+ reddit.com techcrunch.com techmeme.com torrentfreak.com tuaw.com
15
+ tweetmeme.com venturebeat.com wired.com youtube.com zdnet.com zenhabits.net
16
+ }
17
+
18
+ class HostsFileNotWritable < StandardError; end
19
+ class DotFileNotWritable < StandardError; end
20
+
21
+ end
@@ -0,0 +1,9 @@
1
+ # add project-relative load paths
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+
5
+ # require stuff
6
+ require 'work'
7
+ require 'rspec'
8
+ require 'rspec/autorun'
9
+
data/spec/work_spec.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Work do
4
+
5
+ it "should do stuff" do
6
+ 1.should == 1
7
+ nil.should be_nil
8
+ end
9
+
10
+ end
data/work.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'work/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'work'
7
+ s.version = Work::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ['Tim Blair']
10
+ s.email = ['tim@bla.ir']
11
+ s.homepage = 'https://github.com/timblair/work'
12
+ s.summary = 'Anti-procrastination via hosts file manipulation.'
13
+ s.description = 'Anti-procrastination via hosts file manipulation.'
14
+
15
+ s.rubyforge_project = 'work'
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ['lib']
21
+
22
+ s.add_dependency 'sys-uname', '>= 0.8.5'
23
+
24
+ s.add_development_dependency 'rspec', '>= 2.5.0'
25
+ s.add_development_dependency 'yard', '>= 0.6.4'
26
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: work
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Tim Blair
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-05-17 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: sys-uname
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 53
29
+ segments:
30
+ - 0
31
+ - 8
32
+ - 5
33
+ version: 0.8.5
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 27
45
+ segments:
46
+ - 2
47
+ - 5
48
+ - 0
49
+ version: 2.5.0
50
+ type: :development
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: yard
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 15
61
+ segments:
62
+ - 0
63
+ - 6
64
+ - 4
65
+ version: 0.6.4
66
+ type: :development
67
+ version_requirements: *id003
68
+ description: Anti-procrastination via hosts file manipulation.
69
+ email:
70
+ - tim@bla.ir
71
+ executables:
72
+ - play
73
+ - work
74
+ extensions: []
75
+
76
+ extra_rdoc_files: []
77
+
78
+ files:
79
+ - .gitignore
80
+ - .rspec
81
+ - Gemfile
82
+ - Gemfile.lock
83
+ - LICENSE
84
+ - README.md
85
+ - Rakefile
86
+ - bin/play
87
+ - bin/work
88
+ - lib/work.rb
89
+ - lib/work/dotfile.rb
90
+ - lib/work/teacher.rb
91
+ - lib/work/version.rb
92
+ - spec/spec_helper.rb
93
+ - spec/work_spec.rb
94
+ - work.gemspec
95
+ homepage: https://github.com/timblair/work
96
+ licenses: []
97
+
98
+ post_install_message:
99
+ rdoc_options: []
100
+
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ hash: 3
109
+ segments:
110
+ - 0
111
+ version: "0"
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ hash: 3
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ requirements: []
122
+
123
+ rubyforge_project: work
124
+ rubygems_version: 1.7.2
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Anti-procrastination via hosts file manipulation.
128
+ test_files:
129
+ - spec/spec_helper.rb
130
+ - spec/work_spec.rb
131
+ has_rdoc: