domodoro 0.0.1

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