work 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: