domodoro 0.0.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/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ *.rbc
6
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in domodoro.gemspec
4
+ gemspec
5
+
6
+ gem 'guard'
7
+ gem 'guard-minitest'
8
+ gem 'rb-fsevent'
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard 'minitest' do
2
+ watch(%r|^test/(.*)_test\.rb|)
3
+ watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
4
+ watch(%r|^test/test_helper\.rb|) { "test" }
5
+ end
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+ desc "Run Domodoro tests"
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "test"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ t.verbose = true
9
+ end
10
+
11
+ task :default => :test
data/Readme.md ADDED
@@ -0,0 +1,70 @@
1
+ # domodoro
2
+
3
+ Distributed pomodoro architecture running on EventMachine.
4
+
5
+ Domodoro uses a pub/sub approach to send scheduled pomodoro events (such as
6
+ 'start working' or 'pomodoro break') to a number of subscribers simultaneously.
7
+
8
+ The subscriber (i.e. the domodoro client) receives those events and triggers
9
+ an appropriate alarm/notification (via Growl for example).
10
+
11
+ The idea behind this is that synchronized pomodoros between coworkers are a
12
+ win, but difficult to implement with traditional software, because of the
13
+ following reasons:
14
+
15
+ * Using local pomodoro timers/software makes pomodoro cycles unsynced between
16
+ different coworkers, so that one may have a pomodoro break while others are
17
+ still working and that may put at risk their ability to focus.
18
+
19
+ * Using a global pomodoro (for example, alarms for the entire office) **does**
20
+ annoy the hell out of whoever does'nt want/can't benefit from pomodoro
21
+ cycles at a particular moment.
22
+
23
+ * Plus, the "alarms for the entire office" does not work with coworkers that
24
+ may not be in the office (telecommuting workers for example).
25
+
26
+ Solution: a pub/sub architecture where a centralized publisher (the domodoro
27
+ server) broadcasts pomodoro events to whoever wants to subscribe to them, so
28
+ whoever wants to stay synced, can, and who doesn't, can stay out of it.
29
+
30
+ ## Install
31
+
32
+ $ gem install domodoro
33
+
34
+ In the server machine:
35
+
36
+ $ domodoro serve [port]
37
+
38
+ Each of the clients that want to connect must do this:
39
+
40
+ $ domodoro join [ip of the server machine] [port]
41
+
42
+ The clients will receive notifications via sound/growl (configurable in a
43
+ `~/.domodororc` file).
44
+
45
+ ## Caveats
46
+
47
+ * Sound notifications use `afplay`, which ships by default with OSX.
48
+ If you're not using OSX, try to install the `afplay` program manually or...
49
+ send a patch to make it work with your OS :)
50
+
51
+ * The pomodoro schedule is (as of v0.0.1) hard-coded. It starts at 8:00 AM,
52
+ stops at 13:00 for lunch, and starts again at 13:20. In the following
53
+ versions this will be freely configurable.
54
+
55
+ ## Configuration
56
+
57
+ By default, both sound and visual notifications are displayed on each event.
58
+ If you want to configure this, create a file in your home directory named
59
+ `.domodororc` with some YAML configuration:
60
+
61
+ $ touch ~/.domodororc
62
+ $ echo "visual: true" >> ~/.domodororc
63
+ $ echo "sound: false" >> ~/.domodororc
64
+
65
+ ## Copyright
66
+
67
+ Copyright (c) 2011 Josep M. Bach. Released under the MIT license.
68
+
69
+
70
+
data/assets/start.wav ADDED
Binary file
data/assets/stop.wav ADDED
Binary file
data/bin/domodoro ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ require 'domodoro'
3
+
4
+ action = ARGV.shift
5
+ args = ARGV
6
+
7
+ Domodoro.start(action, *args)
data/domodoro.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "domodoro/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "domodoro"
7
+ s.version = Domodoro::VERSION
8
+ s.authors = ["Josep M. Bach"]
9
+ s.email = ["josep.m.bach@gmail.com"]
10
+ s.homepage = "http://github.com/txus/domodoro"
11
+ s.summary = %q{Distributed Pomodoro for the masses}
12
+ s.description = %q{Distributed Pomodoro for the masses}
13
+
14
+ s.rubyforge_project = "domodoro"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_runtime_dependency 'eventmachine'
22
+ s.add_runtime_dependency 'notify'
23
+ s.add_development_dependency 'minitest'
24
+ s.add_development_dependency 'mocha'
25
+ s.add_development_dependency 'purdytest'
26
+ end
@@ -0,0 +1,44 @@
1
+ module Domodoro
2
+ class Channel < EM::Channel
3
+ def broadcast(hour, min)
4
+ if ENV['DEBUG']
5
+ puts 'DEBUG MODE: Start on even minutes, stop on odd minutes'
6
+ if min % 2 == 0
7
+ puts "#{Time.now} - Starting pomodoro!"
8
+ self << :start
9
+ else
10
+ puts "#{Time.now} - Pomodoro break!"
11
+ self << :stop
12
+ end
13
+ return
14
+ end
15
+
16
+ if (hour >= 8 && hour < 13)
17
+ morning(min)
18
+ elsif (hour >= 13 && min >= 20) &&
19
+ afternoon(min)
20
+ end
21
+ end
22
+ def morning(min)
23
+ case min
24
+ when 0, 30
25
+ puts "#{Time.now} - Starting pomodoro!"
26
+ self << :start
27
+ when 25, 55
28
+ puts "#{Time.now} - Pomodoro break!"
29
+ self << :stop
30
+ end
31
+ end
32
+
33
+ def afternoon(min)
34
+ case min
35
+ when 20, 50
36
+ puts "#{Time.now} - Starting pomodoro!"
37
+ self << :start
38
+ when 45, 15
39
+ puts "#{Time.now} - Pomodoro break!"
40
+ self << :stop
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,77 @@
1
+ require 'notify'
2
+
3
+ module Domodoro
4
+ class Client
5
+ class << self
6
+
7
+ def start(host, port='9111')
8
+ Config.load
9
+ puts "#{Time.now} - Domodoro listening on #{host}:#{port}"
10
+ puts "Visual notifications: #{Config.visual}"
11
+ puts "Sound notifications: #{Config.sound}\n"
12
+
13
+ EM.run do
14
+ EM.connect(host, port) do |c|
15
+ c.extend EM::P::LineText2
16
+ def c.receive_line(line)
17
+ case line
18
+ when /start/
19
+ puts " - Starting pomodoro!"
20
+ Client.work
21
+ when /stop/
22
+ puts " - Pomodoro break!"
23
+ Client.break
24
+ end
25
+ end
26
+ end
27
+ EM.add_periodic_timer(1) do
28
+ EM.next_tick do
29
+ print_time
30
+ end
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ def work
37
+ EM.defer do
38
+ if Config.visual
39
+ Notify.notify "Domodoro", "Time to work!"
40
+ end
41
+ if Config.sound
42
+ system("afplay #{path_to('start.wav')}")
43
+ end
44
+ end
45
+ end
46
+
47
+ def break
48
+ EM.defer do
49
+ if Config.visual
50
+ Notify.notify "Domodoro", "Take a 5 min. break."
51
+ end
52
+ if Config.sound
53
+ system("afplay #{path_to('stop.wav')}")
54
+ end
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def path_to(asset)
61
+ File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'assets', asset))
62
+ end
63
+
64
+ def print_time
65
+ hour = Time.now.hour.to_s.rjust(2, '0')
66
+ min = Time.now.min.to_s.rjust(2, '0')
67
+ secs = Time.now.sec.to_s.rjust(2, '0')
68
+ $stdout.print "\r"
69
+ $stdout.print " " * 20
70
+ $stdout.print "\r"
71
+ $stdout.print "#{hour}:#{min}:#{secs}"
72
+ $stdout.flush
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,20 @@
1
+ require 'yaml'
2
+
3
+ module Domodoro
4
+ module Config
5
+ attr_accessor :visual, :sound
6
+ extend self
7
+
8
+ def load
9
+ if File.exist?(File.expand_path('~/.domodororc'))
10
+ file = YAML.load(File.read(File.expand_path('~/.domodororc')))
11
+
12
+ self.visual = file['visual']
13
+ self.sound = file['sound']
14
+ else
15
+ self.visual = true
16
+ self.sound = true
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,49 @@
1
+ module Domodoro
2
+ class Server < EM::Connection
3
+ attr_reader :channel, :sid
4
+
5
+ class << self
6
+ def start(host='127.0.0.1', port='9111')
7
+ puts "#{Time.now} - Domodoro serving at #{host}:#{port}"
8
+ EM.run do
9
+ channel = Channel.new
10
+
11
+ EM.start_server(host, port, self, channel)
12
+
13
+ EM.add_periodic_timer(1) do
14
+ if Time.now.sec == 0
15
+ channel.broadcast(Time.now.hour, Time.now.min)
16
+ else
17
+ EM.next_tick do
18
+ print_time
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ def print_time
26
+ hour = Time.now.hour.to_s.rjust(2, '0')
27
+ min = Time.now.min.to_s.rjust(2, '0')
28
+ secs = Time.now.sec.to_s.rjust(2, '0')
29
+ $stdout.print "\r"
30
+ $stdout.print " " * 20
31
+ $stdout.print "\r"
32
+ $stdout.print "#{hour}:#{min}:#{secs}"
33
+ $stdout.flush
34
+ end
35
+ end
36
+
37
+ def initialize(channel)
38
+ @channel = channel
39
+ end
40
+
41
+ def post_init
42
+ @sid = channel.subscribe { |m| send_data "#{m.inspect}\n" }
43
+ end
44
+
45
+ def unbind
46
+ channel.unsubscribe @sid
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ module Domodoro
2
+ VERSION = "0.0.1"
3
+ end
data/lib/domodoro.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'eventmachine'
2
+
3
+ require "domodoro/version"
4
+ require "domodoro/config"
5
+ require "domodoro/channel"
6
+ require "domodoro/server"
7
+ require "domodoro/client"
8
+
9
+ module Domodoro
10
+ extend self
11
+
12
+ def start(action, *args)
13
+ case action
14
+ when 'serve', 'server'
15
+ Server.start(*args)
16
+ when 'join', 'connect'
17
+ Client.start(*args)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,133 @@
1
+ require 'test_helper'
2
+
3
+ module Domodoro
4
+ describe Channel do
5
+ before do
6
+ @channel = Channel.new
7
+ end
8
+
9
+ it 'is an EventMachine channel' do
10
+ assert @channel.is_a?(EM::Channel)
11
+ end
12
+
13
+ describe 'broadcast' do
14
+ describe 'in the morning' do
15
+ it 'broadcasts from 8:00 until 12:59' do
16
+ @channel.expects(:morning).with(5).never
17
+ @channel.expects(:morning).with(10).once
18
+ @channel.expects(:morning).with(15).once
19
+ @channel.expects(:morning).with(20).once
20
+ @channel.expects(:morning).with(25).once
21
+ @channel.expects(:morning).with(30).once
22
+ @channel.expects(:morning).with(35).never
23
+
24
+ min = 0
25
+ (7..13).each do |hour|
26
+ min += 5
27
+ @channel.broadcast(hour, min)
28
+ end
29
+ end
30
+ end
31
+
32
+ describe 'in the afternoon' do
33
+ it 'broadcasts from 13:20 on' do
34
+ @channel.expects(:afternoon).with(5).never
35
+ @channel.expects(:afternoon).with(10).never
36
+ @channel.expects(:afternoon).with(15).never
37
+ @channel.expects(:afternoon).with(20).once
38
+ @channel.expects(:afternoon).with(25).once
39
+ @channel.expects(:afternoon).with(30).once
40
+ @channel.expects(:afternoon).with(35).once
41
+
42
+ min = 0
43
+ (13..19).each do |hour|
44
+ min += 5
45
+ @channel.broadcast(hour, min)
46
+ end
47
+ end
48
+ end
49
+
50
+ it 'does not broadcast during lunch time' do
51
+ %w(morning afternoon).each do |timespan|
52
+ @channel.expects(timespan).with(5).never
53
+ end
54
+
55
+ (0..19).each do |min|
56
+ @channel.broadcast(13, min)
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '#morning' do
62
+ describe 'pomodoro starts' do
63
+ it 'broadcasts a :start message when the time is XX:00' do
64
+ @channel.expects(:<<).with(:start)
65
+ @channel.morning 0
66
+ end
67
+
68
+ it 'broadcasts a :start message when the time is XX:30' do
69
+ @channel.expects(:<<).with(:start)
70
+ @channel.morning 30
71
+ end
72
+ end
73
+
74
+ describe 'pomodoro stops' do
75
+ it 'broadcasts a :stop message when the time is XX:25' do
76
+ @channel.expects(:<<).with(:stop)
77
+ @channel.morning 25
78
+ end
79
+
80
+ it 'broadcasts a :stop message when the time is XX:55' do
81
+ @channel.expects(:<<).with(:stop)
82
+ @channel.morning 55
83
+ end
84
+ end
85
+
86
+ it 'does not broadcast anything at other times' do
87
+ @channel.expects(:<<).never
88
+
89
+ @channel.morning 5
90
+ @channel.morning 10
91
+ @channel.morning 20
92
+ @channel.morning 40
93
+ @channel.morning 50
94
+ end
95
+ end
96
+
97
+ describe '#afternoon' do
98
+ describe 'pomodoro starts' do
99
+ it 'broadcasts a :start message when the time is XX:20' do
100
+ @channel.expects(:<<).with(:start)
101
+ @channel.afternoon 20
102
+ end
103
+
104
+ it 'broadcasts a :start message when the time is XX:50' do
105
+ @channel.expects(:<<).with(:start)
106
+ @channel.afternoon 50
107
+ end
108
+ end
109
+
110
+ describe 'pomodoro stops' do
111
+ it 'broadcasts a :stop message when the time is XX:45' do
112
+ @channel.expects(:<<).with(:stop)
113
+ @channel.afternoon 45
114
+ end
115
+
116
+ it 'broadcasts a :stop message when the time is XX:15' do
117
+ @channel.expects(:<<).with(:stop)
118
+ @channel.afternoon 15
119
+ end
120
+ end
121
+
122
+ it 'does not broadcast anything at other times' do
123
+ @channel.expects(:<<).never
124
+
125
+ @channel.afternoon 5
126
+ @channel.afternoon 10
127
+ @channel.afternoon 25
128
+ @channel.afternoon 40
129
+ @channel.afternoon 55
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,160 @@
1
+ require 'test_helper'
2
+
3
+ module ExampleServer; end
4
+
5
+ module Domodoro
6
+ describe Client do
7
+ include EM::MiniTest::Spec
8
+
9
+ it 'calls .work when receives :start', :timeout => 0.3 do
10
+ EM.start_server '127.0.0.1', 12345, ExampleServer do |conn|
11
+ conn.send_data ":start\n"
12
+ end
13
+
14
+ Client.expects(:work)
15
+
16
+ Client.start '127.0.0.1', 12345
17
+
18
+ EM.add_timer(0.2) do
19
+ mocha_verify
20
+ done!
21
+ end
22
+
23
+ wait!
24
+ end
25
+
26
+ it 'calls .break when receives :stop', :timeout => 0.3 do
27
+ EM.start_server '127.0.0.1', 12345, ExampleServer do |conn|
28
+ conn.send_data ":stop\n"
29
+ end
30
+
31
+ Client.expects(:break)
32
+
33
+ Client.start '127.0.0.1', 12345
34
+
35
+ EM.add_timer(0.2) do
36
+ mocha_verify
37
+ done!
38
+ end
39
+
40
+ wait!
41
+ end
42
+
43
+ describe '.work' do
44
+ describe 'if sound is activated' do
45
+ it 'plays a sound', :timeout => 0.2 do
46
+ Config.stubs(:sound).returns true
47
+ Client.expects(:system)
48
+ Client.work
49
+
50
+ EM.add_timer(0.1) do
51
+ mocha_verify
52
+ done!
53
+ end
54
+ wait!
55
+ end
56
+ end
57
+
58
+ describe 'otherwise' do
59
+ it 'does not play a sound', :timeout => 0.2 do
60
+ Config.stubs(:sound).returns false
61
+ Client.expects(:system).never
62
+ Client.work
63
+
64
+ EM.add_timer(0.1) do
65
+ mocha_verify
66
+ done!
67
+ end
68
+ wait!
69
+ end
70
+ end
71
+
72
+ describe 'if visual is activated' do
73
+ it 'displays a visual notification', :timeout => 0.2 do
74
+ Config.stubs(:visual).returns true
75
+ Notify.expects(:notify)
76
+ Client.work
77
+
78
+ EM.add_timer(0.1) do
79
+ mocha_verify
80
+ done!
81
+ end
82
+ wait!
83
+ end
84
+ end
85
+
86
+ describe 'otherwise' do
87
+ it 'does not display any visual notification', :timeout => 0.2 do
88
+ Config.stubs(:visual).returns false
89
+ Notify.expects(:notify).never
90
+ Client.work
91
+
92
+ EM.add_timer(0.1) do
93
+ mocha_verify
94
+ done!
95
+ end
96
+ wait!
97
+ end
98
+ end
99
+ end
100
+
101
+ describe '.break' do
102
+ describe 'if sound is activated' do
103
+ it 'plays a sound', :timeout => 0.2 do
104
+ Config.stubs(:sound).returns true
105
+ Client.expects(:system)
106
+ Client.break
107
+
108
+ EM.add_timer(0.1) do
109
+ mocha_verify
110
+ done!
111
+ end
112
+ wait!
113
+ end
114
+
115
+ end
116
+
117
+ describe 'otherwise' do
118
+ it 'does not play a sound', :timeout => 0.2 do
119
+ Config.stubs(:sound).returns false
120
+ Client.expects(:system).never
121
+ Client.break
122
+
123
+ EM.add_timer(0.1) do
124
+ mocha_verify
125
+ done!
126
+ end
127
+ wait!
128
+ end
129
+ end
130
+
131
+ describe 'if visual is activated' do
132
+ it 'displays a visual notification', :timeout => 0.2 do
133
+ Config.stubs(:visual).returns true
134
+ Notify.expects(:notify)
135
+ Client.break
136
+
137
+ EM.add_timer(0.1) do
138
+ mocha_verify
139
+ done!
140
+ end
141
+ wait!
142
+ end
143
+ end
144
+
145
+ describe 'otherwise' do
146
+ it 'does not display any visual notification', :timeout => 0.2 do
147
+ Config.stubs(:visual).returns false
148
+ Notify.expects(:notify).never
149
+ Client.break
150
+
151
+ EM.add_timer(0.1) do
152
+ mocha_verify
153
+ done!
154
+ end
155
+ wait!
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ module Domodoro
4
+ describe Config do
5
+ describe 'if ~/.domodororc exists' do
6
+ it 'loads the config from a ~/.domodororc file' do
7
+ File.stubs(:exist?).returns true
8
+ File.stubs(:read).returns """
9
+ visual: true
10
+ sound: false
11
+ """
12
+ Domodoro::Config.load
13
+
14
+ assert_equal true, Domodoro::Config.visual
15
+ assert_equal false, Domodoro::Config.sound
16
+ end
17
+ end
18
+
19
+ describe 'otherwise' do
20
+ it 'sets both options to true' do
21
+ File.stubs(:exist?).returns false
22
+
23
+ Domodoro::Config.load
24
+
25
+ assert_equal true, Domodoro::Config.visual
26
+ assert_equal true, Domodoro::Config.sound
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,65 @@
1
+ require 'test_helper'
2
+
3
+ module Domodoro
4
+ describe Server do
5
+ include EM::MiniTest::Spec
6
+
7
+ before do
8
+ @channel = Channel.new
9
+ end
10
+
11
+ it 'initializes with a channel' do
12
+ server = Domodoro::Server.new(nil, @channel)
13
+ assert_equal @channel, server.channel
14
+ end
15
+
16
+ it 'repeats every message broadcasted to the channel' do
17
+ server = Server.new(nil, @channel)
18
+ EM.start_server('127.0.0.1', 8888, Server, :app => server)
19
+
20
+ server.expects(:send_data).with(":start\n")
21
+
22
+ @channel << :start
23
+ end
24
+
25
+ describe '.start' do
26
+ it 'opens a server with a new channel' do
27
+ Channel.expects(:new).returns @channel
28
+ EM.expects(:start_server).with('0.0.0.0', '8888', Server, @channel)
29
+
30
+ Server.start('0.0.0.0', '8888')
31
+ end
32
+
33
+ it 'adds a timer by second that calls broadcast every minute', :timeout => 4 do
34
+ Channel.expects(:new).returns(@channel).at_least(1)
35
+ Server.start('0.0.0.0', '8888')
36
+
37
+ module Tick
38
+ attr_accessor :num
39
+ extend self
40
+ end
41
+
42
+ Tick.num = 0
43
+
44
+ now = stub
45
+ Time.expects(:now).at_least(3).returns now
46
+ now.stubs(:hour).returns 0
47
+ now.stubs(:min).returns 0
48
+ now.stubs(:sec).returns 0
49
+
50
+ def @channel.broadcast(*args)
51
+ puts 'tick'
52
+ Tick.num += 1
53
+ end
54
+
55
+ EM.add_timer(3.5) do
56
+ assert_equal 3, Tick.num
57
+ done!
58
+ end
59
+
60
+ wait!
61
+ end
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ describe Domodoro do
4
+ describe '.start' do
5
+
6
+ describe 'as a server' do
7
+ it 'spawns a Domodoro server' do
8
+ port = stub
9
+ Domodoro::Server.expects(:start).with(port)
10
+
11
+ Domodoro.start 'serve', port
12
+ end
13
+ end
14
+
15
+ describe 'as a client' do
16
+ it 'starts a Domodoro client' do
17
+ host, port = stub, stub
18
+ Domodoro::Client.expects(:start).with(host, port)
19
+
20
+ Domodoro.start 'join', host, port
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,103 @@
1
+ require 'rubygems'
2
+ require 'eventmachine'
3
+
4
+ module EM # :nodoc:
5
+ module MiniTest # :nodoc:
6
+ module Spec # :nodoc
7
+ VERSION = '1.1.0' # :nodoc:
8
+
9
+ ##
10
+ # +wait+ indicates that the spec is not expected to be completed when
11
+ # the block is finished running. A call to +done+ is required when using
12
+ # +wait+.
13
+ #
14
+ # # setup my spec to use EM::MiniTest::Spec
15
+ # describe MyClass do
16
+ # include EM::MiniTest::Spec
17
+ #
18
+ # # The call to defer will return immediately, so the spec code
19
+ # # needs to keep running until callback is called.
20
+ # it "does some async things" do
21
+ # defer_me = lambda do
22
+ # # some async stuff
23
+ # end
24
+ #
25
+ # callback = lambda do
26
+ # done!
27
+ # end
28
+ #
29
+ # EM.defer defer_me, callback
30
+ #
31
+ # wait!
32
+ # end
33
+ def wait
34
+ @wait = true
35
+ end
36
+ alias wait! wait
37
+
38
+ ##
39
+ # Indicates that an async spec is finished. See +wait+ for example usage.
40
+ def done
41
+ EM.cancel_timer(@timeout)
42
+ EM.stop
43
+ end
44
+ alias done! done
45
+
46
+ ##
47
+ # A helper method for the use case of waiting for some operation to
48
+ # complete that is not necessarily under the control of the spec code.
49
+ #
50
+ # # These are exactly equivalent
51
+ # it "waits with the helper" do
52
+ # wait_for do
53
+ # assert true
54
+ # end
55
+ # end
56
+ #
57
+ # it "waits manually" do
58
+ # EM.next_tick do
59
+ # assert true
60
+ # done!
61
+ # end
62
+ #
63
+ # wait!
64
+ # end
65
+ def wait_for
66
+ EM.next_tick do
67
+ yield
68
+ done!
69
+ end
70
+
71
+ wait!
72
+ end
73
+
74
+ def self.included base # :nodoc:
75
+ base.extend(ClassMethods)
76
+ end
77
+
78
+ module ClassMethods # :nodoc:
79
+ def it *args, &block # :nodoc:
80
+ return super unless block_given?
81
+
82
+ timeout = 0.1
83
+ if args.last.is_a?(Hash) && args.last[:timeout]
84
+ timeout = args.pop[:timeout]
85
+ end
86
+
87
+ super do
88
+ @wait = false
89
+
90
+ EM.run do
91
+ @timeout = EM.add_timer(timeout) do
92
+ flunk "test timed out!"
93
+ end
94
+
95
+ instance_eval(&block)
96
+ done! unless @wait
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+
3
+ gem 'minitest'
4
+ require 'mocha'
5
+ require 'minitest/spec'
6
+ require 'purdytest'
7
+ require 'minitest/autorun'
8
+
9
+ Dir['test/support/*.rb'].each do |file|
10
+ require file
11
+ end
12
+
13
+ require 'domodoro'
14
+
15
+ class MiniTest::Unit::TestCase
16
+ include Mocha::API
17
+ def setup
18
+ mocha_setup
19
+ end
20
+ def teardown
21
+ mocha_teardown
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: domodoro
3
+ version: !ruby/object:Gem::Version
4
+ hash: 856480538658449761
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Josep M. Bach
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-08-28 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: eventmachine
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 2002549777813010636
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: notify
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 2002549777813010636
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: minitest
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 2002549777813010636
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :development
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: mocha
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 2002549777813010636
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ type: :development
76
+ version_requirements: *id004
77
+ - !ruby/object:Gem::Dependency
78
+ name: purdytest
79
+ prerelease: false
80
+ requirement: &id005 !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 2002549777813010636
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ type: :development
90
+ version_requirements: *id005
91
+ description: Distributed Pomodoro for the masses
92
+ email:
93
+ - josep.m.bach@gmail.com
94
+ executables:
95
+ - domodoro
96
+ extensions: []
97
+
98
+ extra_rdoc_files: []
99
+
100
+ files:
101
+ - .gitignore
102
+ - Gemfile
103
+ - Guardfile
104
+ - Rakefile
105
+ - Readme.md
106
+ - assets/start.wav
107
+ - assets/stop.wav
108
+ - bin/domodoro
109
+ - domodoro.gemspec
110
+ - lib/domodoro.rb
111
+ - lib/domodoro/channel.rb
112
+ - lib/domodoro/client.rb
113
+ - lib/domodoro/config.rb
114
+ - lib/domodoro/server.rb
115
+ - lib/domodoro/version.rb
116
+ - test/domodoro/channel_test.rb
117
+ - test/domodoro/client_test.rb
118
+ - test/domodoro/config_test.rb
119
+ - test/domodoro/server_test.rb
120
+ - test/domodoro_test.rb
121
+ - test/support/em-minitest.rb
122
+ - test/test_helper.rb
123
+ has_rdoc: true
124
+ homepage: http://github.com/txus/domodoro
125
+ licenses: []
126
+
127
+ post_install_message:
128
+ rdoc_options: []
129
+
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ hash: 2002549777813010636
138
+ segments:
139
+ - 0
140
+ version: "0"
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ none: false
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ hash: 2002549777813010636
147
+ segments:
148
+ - 0
149
+ version: "0"
150
+ requirements: []
151
+
152
+ rubyforge_project: domodoro
153
+ rubygems_version: 1.5.2
154
+ signing_key:
155
+ specification_version: 3
156
+ summary: Distributed Pomodoro for the masses
157
+ test_files:
158
+ - test/domodoro/channel_test.rb
159
+ - test/domodoro/client_test.rb
160
+ - test/domodoro/config_test.rb
161
+ - test/domodoro/server_test.rb
162
+ - test/domodoro_test.rb
163
+ - test/support/em-minitest.rb
164
+ - test/test_helper.rb