cheeky-dreams 0.0.1 → 0.0.2

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/Gemfile CHANGED
@@ -1,7 +1,6 @@
1
1
  source "http://rubygems.org"
2
2
  # Add dependencies required to use your gem here.
3
3
  # Example:
4
- gem "flt", ">= 1.3.0"
5
4
 
6
5
  # Add dependencies to develop your gem here.
7
6
  # Include everything needed to run rake, tests, features, etc.
data/Gemfile.lock CHANGED
@@ -2,7 +2,6 @@ GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
4
  diff-lcs (1.1.3)
5
- flt (1.3.0)
6
5
  git (1.2.5)
7
6
  jeweler (1.6.4)
8
7
  bundler (~> 1.0)
@@ -24,7 +23,6 @@ PLATFORMS
24
23
 
25
24
  DEPENDENCIES
26
25
  bundler (~> 1.0.0)
27
- flt (>= 1.3.0)
28
26
  jeweler (~> 1.6.4)
29
27
  rcov
30
28
  rspec (>= 2.3.0)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
@@ -0,0 +1,65 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "cheeky-dreams"
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["simon"]
12
+ s.date = "2011-11-02"
13
+ s.description = "For controlling dream cheeky usb light"
14
+ s.email = "simojenki@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "cheeky-dreams.gemspec",
29
+ "lib/cheeky-dreams.rb",
30
+ "spec/cheeky-dreams_spec.rb",
31
+ "spec/spec_helper.rb",
32
+ "spec/support/collecting_auditor.rb",
33
+ "spec/support/stub_driver.rb",
34
+ "spec/support/stub_effect.rb",
35
+ "spec/support/within.rb",
36
+ "spec/test.rb"
37
+ ]
38
+ s.homepage = "http://github.com/simojenki/cheeky-dreams"
39
+ s.licenses = ["MIT"]
40
+ s.require_paths = ["lib"]
41
+ s.rubygems_version = "1.8.10"
42
+ s.summary = "For controlling dream cheeky usb light"
43
+
44
+ if s.respond_to? :specification_version then
45
+ s.specification_version = 3
46
+
47
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
48
+ s.add_development_dependency(%q<rspec>, [">= 2.3.0"])
49
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
50
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
51
+ s.add_development_dependency(%q<rcov>, [">= 0"])
52
+ else
53
+ s.add_dependency(%q<rspec>, [">= 2.3.0"])
54
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
55
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
56
+ s.add_dependency(%q<rcov>, [">= 0"])
57
+ end
58
+ else
59
+ s.add_dependency(%q<rspec>, [">= 2.3.0"])
60
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
61
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
62
+ s.add_dependency(%q<rcov>, [">= 0"])
63
+ end
64
+ end
65
+
data/lib/cheeky-dreams.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'thread'
2
- require 'flt'
3
2
 
4
3
  module CheekyDreams
5
4
 
@@ -18,13 +17,20 @@ module CheekyDreams
18
17
  position_between(a[2], b[2], ratio),
19
18
  ]
20
19
  end
20
+ def rgb_between a, b, ratio
21
+ CheekyDreams::rgb_between a, b, ratio
22
+ end
21
23
 
22
24
  def self.position_between a, b, ratio
23
25
  return b if ratio >= 1.0
24
- ((b - a) * ratio) + a
26
+ (((b - a) * ratio) + a).floor
27
+ end
28
+ def position_between a, b, ratio
29
+ CheekyDreams::position_between a, b, ratio
25
30
  end
26
31
 
27
32
  COLOURS = {
33
+ :off => rgb(0, 0, 0),
28
34
  :red => rgb(255, 0, 0),
29
35
  :green => rgb(0, 255, 0),
30
36
  :blue => rgb(0, 0, 255),
@@ -41,7 +47,8 @@ module CheekyDreams
41
47
  raise "Unknown colour '#{colour}'" unless COLOURS.has_key?(colour)
42
48
  COLOURS[colour]
43
49
  when Array
44
- colour
50
+ raise "Invalid rgb #{colour}" unless colour.length == 3 && colour.all? { |c| c.is_a? Fixnum }
51
+ rgb(colour[0], colour[1], colour[2])
45
52
  else
46
53
  raise "Unsupported colour type #{colour}"
47
54
  end
@@ -50,6 +57,15 @@ module CheekyDreams
50
57
  CheekyDreams::rgb_for colour
51
58
  end
52
59
 
60
+ def stderr_auditor
61
+ Class.new do
62
+ def unhandled_error e
63
+ STDERR.puts e.message
64
+ STDERR.puts e.backtrace.join("\n")
65
+ end
66
+ end.new
67
+ end
68
+
53
69
  def stdout_driver
54
70
  Class.new do
55
71
  def go rgb
@@ -68,81 +84,157 @@ module CheekyDreams
68
84
  end.new
69
85
  end
70
86
 
71
- def cycle colours, freq
72
- Effect::Cycle.new colours, freq
73
- end
74
-
75
- def solid colour
76
- Effect::Solid.new colour
77
- end
78
-
79
- def fade from, to, over_how_long
80
- Effect::Fade.new from, to, over_how_long
87
+ def find_dream_cheeky_usb_device
88
+ Device::DreamCheeky.new(File.dirname(Dir.glob('/sys/devices/**/red').first))
81
89
  end
82
90
 
83
- def func freq, &block
84
- Effect::Func.new freq, block
91
+ module Device
92
+ class DreamCheeky
93
+ attr_reader :path
94
+ def initialize path, max_threshold = 50
95
+ @path, @max_threshold = path, max_threshold
96
+ end
97
+
98
+ def go rgb
99
+ system "echo #{using_threshold(rgb[0])} > #{path}/red"
100
+ system "echo #{using_threshold(rgb[1])} > #{path}/green"
101
+ system "echo #{using_threshold(rgb[2])} > #{path}/blue"
102
+ end
103
+
104
+ private
105
+ def using_threshold colour
106
+ colour if @threshold == 255
107
+ ((colour / 255.to_f) * @max_threshold).floor
108
+ end
109
+ end
85
110
  end
86
111
 
87
112
  module Effect
88
113
  class Effect
89
- include Flt
90
114
  include CheekyDreams
115
+ include Math
116
+
117
+ attr_reader :freq
118
+
119
+ def initialize freq
120
+ @freq = freq
121
+ end
91
122
  end
92
123
 
124
+ class Throb2 < Effect
125
+ def initialize freq, amplitude, centre
126
+ super freq
127
+ @amplitude, @centre, @count = amplitude, centre, 1
128
+ end
129
+
130
+ def next current_colour
131
+ x = freq * (@count += 1)
132
+ v = sin(x) * @amplitude + @centre
133
+ [v, 0, 0]
134
+ end
135
+ end
136
+
137
+ class Throb < Effect
138
+ attr_reader :r_amp, :r_centre, :g_amp, :g_centre, :b_amp, :b_centre
139
+
140
+ def initialize freq, from, to
141
+ super freq
142
+ @r_centre, @r_amp = centre_and_amp from[0], to[0]
143
+ @g_centre, @g_amp = centre_and_amp from[1], to[1]
144
+ @b_centre, @b_amp = centre_and_amp from[2], to[2]
145
+ @count = 1
146
+ end
147
+
148
+ def next current_colour
149
+ x = sin(freq * @count)
150
+ r = x * r_amp + r_centre
151
+ g = x * g_amp + g_centre
152
+ b = x * b_amp + b_centre
153
+ # x = freq * (@count += 1)
154
+ # v = sin(x) * @amplitude + @centre
155
+ # [v, 0, 0]
156
+
157
+ @count += 1
158
+ [r, g, b]
159
+ end
160
+
161
+ private
162
+ def centre_and_amp from, to
163
+ amp = ((from - to).abs / 2.0).floor
164
+ centre = max(from, to) - amp
165
+ [centre, amp]
166
+ end
167
+
168
+ def max a, b
169
+ a > b ? a : b
170
+ end
171
+ end
172
+
173
+
93
174
  class Func < Effect
94
- def initialize freq, block
95
- @freq, @block, @last_change = freq, block, Time.at(0)
175
+ def initialize freq, &block
176
+ super freq
177
+ @block = block
96
178
  end
97
179
 
98
- def next
99
- now = Time.now
100
- if (now - @last_change) >= (DecNum(1)/DecNum(@freq))
101
- @last_change = now
102
- @current = rgb_for(@block.yield)
103
- end
104
- @current
180
+ def next current_colour = nil
181
+ rgb_for(@block.yield(current_colour))
105
182
  end
106
183
  end
107
184
 
108
185
  class Solid < Effect
109
186
  def initialize colour
110
- @rgb = CheekyDreams::rgb_for(colour)
187
+ super 1
188
+ @rgb = rgb_for(colour)
111
189
  end
112
- def next
190
+
191
+ def next current_colour = nil
113
192
  @rgb
114
193
  end
115
194
  end
116
195
 
117
196
  class Cycle < Effect
118
197
  def initialize colours, freq
119
- @colours, @freq, @last_change = colours.cycle, freq, Time.at(0)
198
+ super freq
199
+ @cycle = colours.cycle
120
200
  end
121
201
 
122
- def next
123
- now = Time.now
124
- if (now - @last_change) >= (DecNum(1)/DecNum(@freq))
125
- @last_change = now
126
- @current = rgb_for(@colours.next)
127
- end
128
- @current
202
+ def next current_colour = nil
203
+ rgb_for(@cycle.next)
129
204
  end
130
205
  end
131
206
 
132
207
  class Fade < Effect
133
- def initialize from, to, over_how_long
134
- @from, @to, @over_how_long = from, to, over_how_long
208
+ def initialize from, to, steps, freq
209
+ super freq
210
+ @rgb_from, @rgb_to = rgb_for(from), rgb_for(to)
211
+ @fade = [@rgb_from]
212
+ (1..(steps-1)).each { |i| @fade << rgb_between(@rgb_from, @rgb_to, i / steps.to_f) }
213
+ @fade << @rgb_to
214
+ @index = 0
135
215
  end
136
216
 
137
- def next
138
- now = Time.now
139
- if @started_at == nil
140
- @started_at = now
141
- @from
142
- else
143
- ratio_done = (now - @started_at) / @over_how_long
144
- CheekyDreams.rgb_between(rgb_for(@from), rgb_for(@to), ratio_done)
217
+ def next current_colour = nil
218
+ return @rgb_to if @index >= @fade.length
219
+ next_colour = @fade[@index]
220
+ @index += 1
221
+ next_colour
222
+ end
223
+ end
224
+
225
+ class FadeTo < Effect
226
+ def initialize to, steps, freq
227
+ super freq
228
+ @to, @steps = to, steps
229
+ @fade = nil
230
+ end
231
+
232
+ def next current_colour
233
+ unless @fade
234
+ @fade = Fade.new(current_colour, @to, @steps, freq)
235
+ @fade.next current_colour
145
236
  end
237
+ @fade.next current_colour
146
238
  end
147
239
  end
148
240
  end
@@ -151,53 +243,84 @@ end
151
243
  class Light
152
244
 
153
245
  include CheekyDreams
154
- include Flt
155
246
 
156
- def initialize driver, freq = 5
157
- @driver = driver
247
+ attr_accessor :freq, :auditor
248
+
249
+ def initialize driver
250
+ @driver, @freq, @auditor = driver, 100, stderr_auditor
158
251
  @lock = Mutex.new
159
252
  @effect = nil
160
253
  @on = false
161
- @freq = freq
162
254
  end
163
255
 
164
- def go colour
256
+ def cycle colours, freq = 1
257
+ go(Effect::Cycle.new(colours, freq))
258
+ end
259
+
260
+ def solid colour
261
+ go(Effect::Solid.new(colour))
262
+ end
263
+
264
+ def fade from, to, steps = 10, freq = 1
265
+ go Effect::Fade.new from, to, steps, freq
266
+ end
267
+
268
+ def fade_to to, steps = 10, freq = 1
269
+ go Effect::FadeTo.new to, steps, freq
270
+ end
271
+
272
+ def func freq = 1, &block
273
+ go Effect::Func.new freq, &block
274
+ end
275
+
276
+ def throb freq, amplitude, centre
277
+ go Effect::Throb.new freq, amplitude, centre
278
+ end
279
+
280
+ def go effect
165
281
  @lock.synchronize {
166
- case colour
282
+ case effect
167
283
  when Symbol
168
- @effect = solid(colour)
284
+ @effect = Effect::Solid.new(effect)
169
285
  when Array
170
- @effect = solid(colour)
286
+ @effect = Effect::Solid.new(effect)
171
287
  when Effect::Effect
172
- @effect = colour
288
+ @effect = effect
173
289
  else
174
- raise "Im sorry dave, I'm afraid I can't do that. #{colour}"
290
+ raise "Im sorry dave, I'm afraid I can't do that. #{effect}"
175
291
  end
176
292
  }
293
+ turn_on unless @on
177
294
  end
178
295
 
179
- def on
296
+ private
297
+ def turn_on
180
298
  @on = true
181
- t = Thread.new do
299
+ Thread.new do
300
+ current_effect = nil
182
301
  last_colour = nil
302
+ next_colour_time = nil
183
303
  while @on
184
304
  begin
185
305
  @lock.synchronize {
186
- if @effect
187
- new_colour = @effect.next
188
- if new_colour != last_colour
189
- @driver.go new_colour
190
- last_colour = new_colour
191
- end
306
+ if @effect && current_effect != @effect
307
+ current_effect = @effect
308
+ next_colour_time = Time.at(0)
192
309
  end
193
310
  }
311
+ if current_effect
312
+ if Time.now > next_colour_time
313
+ new_colour = current_effect.next(last_colour)
314
+ @driver.go new_colour
315
+ last_colour = new_colour
316
+ next_colour_time = Time.now + (1 / current_effect.freq.to_f)
317
+ end
318
+ end
194
319
  rescue => e
195
- puts e.message
196
- puts e.backtrace.join("\n")
320
+ auditor.unhandled_error e
197
321
  end
198
- sleep (DecNum(1)/DecNum(@freq))
322
+ sleep (1 / freq.to_f)
199
323
  end
200
324
  end
201
325
  end
202
-
203
326
  end
@@ -1,64 +1,401 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe CheekyDreams do
4
+
5
+ include CheekyDreams
6
+
7
+ describe "find_dream_cheeky_usb_device" do
8
+ it "should locate the rgb files and return the driver" do
9
+ Dir.should_receive(:glob).with('/sys/devices/**/red').and_return(["/sys/devices/some-crazy-pci-bus-stuff/red"])
10
+ driver = find_dream_cheeky_usb_device
11
+ driver.path.should == "/sys/devices/some-crazy-pci-bus-stuff"
12
+ end
13
+ end
14
+
4
15
  describe "position_between" do
16
+ it "should calculate the position as hole numbers" do
17
+ position_between(100, 102, 0.25).should == 100
18
+ position_between(100, 102, 0.5).should == 101
19
+ position_between(100, 102, 0.75).should == 101
20
+ position_between(100, 102, 1).should == 102
21
+ end
22
+
5
23
  it "should calculate the position" do
6
- CheekyDreams.position_between(100, 110, 0.5).should == 105
7
- CheekyDreams.position_between(110, 100, 0.5).should == 105
8
- CheekyDreams.position_between(100, 0, 0.2).should == 80
9
- CheekyDreams.position_between(100, 0, 0.25).should == 75
10
- CheekyDreams.position_between(100, 0, 1).should == 0
24
+ position_between(100, 110, 0.5).should == 105
25
+ position_between(110, 100, 0.5).should == 105
26
+ position_between(100, 0, 0.2).should == 80
27
+ position_between(100, 0, 0.25).should == 75
28
+ position_between(100, 0, 1).should == 0
11
29
  end
12
30
 
13
31
  it "should return the end point when the ration goes above 1" do
14
- CheekyDreams.position_between(100, 1, 1.01).should == 1
15
- CheekyDreams.position_between(96, 99, 999).should == 99
32
+ position_between(100, 1, 1.01).should == 1
33
+ position_between(96, 99, 999).should == 99
16
34
  end
17
35
  end
18
36
 
19
37
  describe "rgb_between" do
20
38
  it "should calculate the position" do
21
- CheekyDreams.rgb_between([100, 50, 0], [110, 20, 0], 0.1).should == [101, 47, 0]
39
+ rgb_between([100, 50, 0], [110, 20, 0], 0.1).should == [101, 47, 0]
40
+ end
41
+ end
42
+
43
+ describe "rgb_for" do
44
+ it "should return rgb array for simple colours" do
45
+ rgb_for(:off).should == [0, 0, 0]
46
+ rgb_for(:red).should == [255, 0, 0]
47
+ rgb_for(:green).should == [0, 255, 0]
48
+ rgb_for(:blue).should == [0, 0, 255]
49
+ end
50
+
51
+ it "should return an rgb array when given one" do
52
+ rgb_for([11, 34, 111]).should == [11, 34, 111]
53
+ end
54
+
55
+ it "should blow up when given meaningless symbol" do
56
+ lambda { rgb_for(:purple_patch) }.should raise_error "Unknown colour 'purple_patch'"
57
+ end
58
+
59
+ it "should blow up when given array that isnt rgb" do
60
+ lambda { rgb_for([1]) }.should raise_error "Invalid rgb [1]"
61
+ lambda { rgb_for([1, 2, 3, 4]) }.should raise_error "Invalid rgb [1, 2, 3, 4]"
62
+ lambda { rgb_for(["a", "b", "c"]) }.should raise_error 'Invalid rgb ["a", "b", "c"]'
63
+ end
64
+
65
+ it "should blow up when given invalid rgb values" do
66
+ lambda { rgb_for([0, 256, 0]) }.should raise_error "Invalid rgb value 0, 256, 0"
67
+ lambda { rgb_for([-1, 0, 0]) }.should raise_error "Invalid rgb value -1, 0, 0"
68
+ lambda { rgb_for([0, 0, 256]) }.should raise_error "Invalid rgb value 0, 0, 256"
22
69
  end
23
70
  end
24
71
  end
25
72
 
26
- describe Light do
73
+ module CheekyDreams::Device
74
+
75
+ include CheekyDreams
76
+
77
+ describe DreamCheeky do
78
+ before :each do
79
+ @device_path = "/device"
80
+ end
81
+
82
+ describe "when the max threshold is 100" do
83
+ before :each do
84
+ @device = DreamCheeky.new @device_path, 100
85
+ end
86
+
87
+ describe "making it go 123,34,255" do
88
+ before :each do
89
+ @device.should_receive(:system).with("echo 48 > /device/red").and_return(true)
90
+ @device.should_receive(:system).with("echo 13 > /device/green").and_return(true)
91
+ @device.should_receive(:system).with("echo 100 > /device/blue").and_return(true)
92
+ end
93
+
94
+ it "should turn the light the correct colours" do
95
+ @device.go [123, 34, 255]
96
+ end
97
+ end
98
+
99
+ describe "making it go 0,1,100" do
100
+ before :each do
101
+ @device.should_receive(:system).with("echo 0 > /device/red").and_return(true)
102
+ @device.should_receive(:system).with("echo 0 > /device/green").and_return(true)
103
+ @device.should_receive(:system).with("echo 39 > /device/blue").and_return(true)
104
+ end
105
+
106
+ it "should turn the light the correct colours" do
107
+ @device.go [0, 1, 100]
108
+ end
109
+ end
110
+ end
111
+
112
+ describe "when the max threshold is 255" do
113
+ before :each do
114
+ @device = DreamCheeky.new @device_path, 255
115
+ end
116
+
117
+ describe "making it go 123,34,255" do
118
+ before :each do
119
+ @device.should_receive(:system).with("echo 123 > /device/red").and_return(true)
120
+ @device.should_receive(:system).with("echo 34 > /device/green").and_return(true)
121
+ @device.should_receive(:system).with("echo 255 > /device/blue").and_return(true)
122
+ end
123
+
124
+ it "should turn the light the correct colours" do
125
+ @device.go [123, 34, 255]
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ module CheekyDreams::Effect
27
133
 
28
134
  include CheekyDreams
29
135
 
30
- class StubDriver
136
+ describe Solid do
137
+ describe "when is symbols" do
138
+ before :each do
139
+ @solid = Solid.new :purple
140
+ end
31
141
 
32
- def initialize
33
- @lock = Mutex.new
142
+ it "should return rgb every time called" do
143
+ @solid.next.should == COLOURS[:purple]
144
+ @solid.next.should == COLOURS[:purple]
145
+ @solid.next.should == COLOURS[:purple]
146
+ end
147
+ end
148
+
149
+ describe "when is random rgb value" do
150
+ before :each do
151
+ @solid = Solid.new [123, 123, 123]
152
+ end
153
+
154
+ it "should return rgb every time called" do
155
+ @solid.next.should == [123, 123, 123]
156
+ @solid.next.should == [123, 123, 123]
157
+ @solid.next.should == [123, 123, 123]
158
+ end
159
+ end
160
+ end
161
+
162
+ describe Cycle do
163
+ before :each do
164
+ @cycle = Cycle.new [:red, :blue, [211, 192, 101]], 22
34
165
  end
166
+
167
+ it "should have a frequency" do
168
+ @cycle.freq.should == 22
169
+ end
170
+
171
+ it "should cycle through the colours as rgb" do
172
+ @cycle.next.should == [255, 0, 0]
173
+ @cycle.next.should == [ 0, 0,255]
174
+ @cycle.next.should == [211, 192, 101]
175
+
176
+ @cycle.next.should == [255, 0, 0]
177
+ @cycle.next.should == [ 0, 0,255]
178
+ @cycle.next.should == [211, 192, 101]
179
+
180
+ @cycle.next.should == [255, 0, 0]
181
+ @cycle.next.should == [ 0, 0,255]
182
+ @cycle.next.should == [211, 192, 101]
183
+ end
184
+ end
185
+
186
+ describe Fade do
187
+ describe "fading between two symbols" do
188
+ before :each do
189
+ @fade = Fade.new :blue, :green, 1, 5
190
+ end
35
191
 
36
- def go colour
37
- @lock.synchronize {
38
- @colour = colour
39
- }
192
+ it "should have a freq of 2" do
193
+ @fade.freq.should == 5
194
+ end
195
+
196
+ it "should be able to provide the steps when asked" do
197
+ @fade.next.should == [ 0, 0, 255]
198
+ @fade.next.should == [ 0, 255, 0]
199
+ @fade.next.should == [ 0, 255, 0]
200
+ @fade.next.should == [ 0, 255, 0]
201
+ end
40
202
  end
41
203
 
42
- def should_become expected_colour
43
- rgb = expected_colour.is_a?(Symbol) ? Light::COLOURS[expected_colour] : expected_colour
44
- start, match = Time.now, false
45
- while ((Time.now - start < 1) && !match) do
46
- @lock.synchronize {
47
- match = rgb == @colour
48
- }
49
- sleep 0.01
204
+ describe "fading between two arbitary rgb values" do
205
+ before :each do
206
+ @fade = Fade.new [100, 100, 100], [110, 90, 0], 10, 2
207
+ end
208
+
209
+ it "should have a freq of 2" do
210
+ @fade.freq.should == 2
50
211
  end
51
- raise "Expected driver to become #{rgb}, and didn't, instead is #{@colour}" unless match
212
+
213
+ it "should be able to provide the steps when asked" do
214
+ @fade.next.should == [100, 100, 100]
215
+ @fade.next.should == [101, 99, 90]
216
+ @fade.next.should == [102, 98, 80]
217
+ @fade.next.should == [103, 97, 70]
218
+ @fade.next.should == [104, 96, 60]
219
+ @fade.next.should == [105, 95, 50]
220
+ @fade.next.should == [106, 94, 40]
221
+ @fade.next.should == [107, 93, 30]
222
+ @fade.next.should == [108, 92, 20]
223
+ @fade.next.should == [109, 91, 10]
224
+ @fade.next.should == [110, 90, 0]
225
+ # and then continue to provide the same colour
226
+ @fade.next.should == [110, 90, 0]
227
+ @fade.next.should == [110, 90, 0]
228
+ end
52
229
  end
53
230
  end
54
231
 
55
- describe "changing colour" do
232
+ describe FadeTo do
233
+ describe "fading to a symbol" do
234
+ before :each do
235
+ @fade_to = FadeTo.new :green, 11, 2
236
+ end
237
+
238
+ it "should have a freq of 2" do
239
+ @fade_to.freq.should == 2
240
+ end
241
+
242
+ it "should be able to gradually go to colour when asked" do
243
+ @fade_to.next([0, 145, 0]).should == [0, 155, 0]
244
+ @fade_to.next([0, 155, 0]).should == [0, 165, 0]
245
+ @fade_to.next([0, 165, 0]).should == [0, 175, 0]
246
+ @fade_to.next([0, 175, 0]).should == [0, 185, 0]
247
+ @fade_to.next([0, 185, 0]).should == [0, 195, 0]
248
+ @fade_to.next([0, 195, 0]).should == [0, 205, 0]
249
+ @fade_to.next([0, 205, 0]).should == [0, 215, 0]
250
+ @fade_to.next([0, 215, 0]).should == [0, 225, 0]
251
+ @fade_to.next([0, 225, 0]).should == [0, 235, 0]
252
+ @fade_to.next([0, 235, 0]).should == [0, 245, 0]
253
+ @fade_to.next([0, 245, 0]).should == [0, 255, 0]
254
+ end
255
+ end
256
+
257
+ describe "fading to a random rgb" do
258
+ before :each do
259
+ @fade_to = FadeTo.new [130, 80, 170], 3, 20
260
+ end
261
+
262
+ it "should have a freq of 20" do
263
+ @fade_to.freq.should == 20
264
+ end
265
+
266
+ it "should be able to gradually go to colour when asked" do
267
+ @fade_to.next([190, 77, 140]).should == [170, 78, 150]
268
+ @fade_to.next([170, 78, 150]).should == [150, 79, 160]
269
+ @fade_to.next([150, 79, 160]).should == [130, 80, 170]
270
+ end
271
+ end
272
+ end
273
+
274
+ describe Func do
275
+ describe "when the block return rgb values" do
276
+ before :each do
277
+ @func = Func.new(22) { |current_colour| [current_colour[0] + 1, current_colour[1] + 1, current_colour[2] + 1] }
278
+ end
279
+
280
+ it "should have a freq of 22" do
281
+ @func.freq.should == 22
282
+ end
283
+
284
+ it "should return the given rgb plus 1 to each of r, g, and b" do
285
+ @func.next([2, 5, 6]).should == [3, 6, 7]
286
+ end
287
+ end
288
+
289
+ describe "when the block return symbol" do
290
+ before :each do
291
+ @func = Func.new(22) { |current_colour| :purple }
292
+ end
293
+
294
+ it "should return the rgb for the symbol" do
295
+ @func.next([2, 5, 6]).should == COLOURS[:purple]
296
+ end
297
+ end
298
+ end
299
+
300
+ describe Throb do
301
+ before :each do
302
+ @throb = Throb.new 10, [100, 100, 100], [250, 50, 0]
303
+ end
304
+
305
+ it "should have r_amp" do
306
+ @throb.r_amp.should == 75
307
+ end
308
+
309
+ it "should have r_centre" do
310
+ @throb.r_centre.should == 175
311
+ end
312
+
313
+ it "should have g_amp" do
314
+ @throb.g_amp.should == 25
315
+ end
316
+
317
+ it "should have g_centre" do
318
+ @throb.g_centre.should == 75
319
+ end
320
+
321
+ it "should have b_amp" do
322
+ @throb.b_amp.should == 50
323
+ end
324
+
325
+ it "should have b_centre" do
326
+ @throb.b_centre.should == 50
327
+ end
328
+ end
329
+ end
330
+
331
+ describe Light do
332
+
333
+ include CheekyDreams
334
+ include Within
335
+
336
+ before :each do
337
+ @driver = StubDriver.new
338
+ @light = Light.new @driver
339
+ end
340
+
341
+ describe "unhandled errors" do
56
342
  before :each do
57
- @driver = StubDriver.new
58
- @light = Light.new @driver
59
- @light.on
343
+ @error = RuntimeError.new "On purpose error"
344
+ @effect = StubEffect.new(20) { raise @error }
345
+ @auditor = CollectingAuditor.new
346
+ @light.auditor = @auditor
347
+ end
348
+
349
+ it 'should notify the auditor' do
350
+ @light.go @effect
351
+ within(1, "auditor should have received '#{@error}'") { [@auditor.has_received?(@error), @auditor.errors] }
352
+ end
353
+ end
354
+
355
+ describe "frequency of effect" do
356
+ describe 'when frequency is 1' do
357
+ before :each do
358
+ @effect = StubEffect.new 1
359
+ end
360
+
361
+ it 'should call the effect almost immediately, and then about 1 second later' do
362
+ @light.go @effect
363
+ sleep 0.1
364
+ @effect.asked_for_colour_count.should be == 1
365
+ sleep 1
366
+ @effect.asked_for_colour_count.should be == 2
367
+ end
368
+ end
369
+
370
+ describe 'when frequency is 10' do
371
+ before :each do
372
+ @effect = StubEffect.new 10
373
+ end
374
+
375
+ it 'should call the effect between 9 and 11 times in the next second' do
376
+ @light.go @effect
377
+ sleep 1
378
+ count = @effect.asked_for_colour_count
379
+ count.should be <= 11
380
+ count.should be >= 9
381
+ end
60
382
  end
61
383
 
384
+ describe 'when frequency is 5' do
385
+ before :each do
386
+ @effect = StubEffect.new 5
387
+ end
388
+
389
+ it 'should call the effect 5 times in the next second' do
390
+ @light.go @effect
391
+ sleep 1
392
+ count = @effect.asked_for_colour_count
393
+ count.should be == 5
394
+ end
395
+ end
396
+ end
397
+
398
+ describe "changing colour" do
62
399
  it "should go red" do
63
400
  @light.go :red
64
401
  @driver.should_become [255,0,0]
@@ -89,7 +426,7 @@ describe Light do
89
426
  end
90
427
 
91
428
  it "should be able to cycle between colours when specified as rgb" do
92
- @light.go cycle([[255, 255, 255], [200, 200, 200], [100, 100, 100]], 10)
429
+ @light.cycle([[255, 255, 255], [200, 200, 200], [100, 100, 100]], 10)
93
430
  @driver.should_become [255, 255, 255]
94
431
  @driver.should_become [200, 200, 200]
95
432
  @driver.should_become [100, 100, 100]
@@ -98,7 +435,7 @@ describe Light do
98
435
  end
99
436
 
100
437
  it "should be able to cycle between colours when specified as symbols" do
101
- @light.go cycle([:red, :green, :blue], 10)
438
+ @light.cycle([:red, :green, :blue], 10)
102
439
  @driver.should_become :red
103
440
  @driver.should_become :green
104
441
  @driver.should_become :blue
@@ -106,6 +443,37 @@ describe Light do
106
443
  @driver.should_become :green
107
444
  end
108
445
 
446
+ it "should be able to fade from one colour to another" do
447
+ @light.fade([100, 100, 0], [105, 95, 0], 5, 2)
448
+ @driver.should_become [101, 99, 0]
449
+ @driver.should_become [102, 98, 0]
450
+ @driver.should_become [103, 97, 0]
451
+ @driver.should_become [104, 96, 0]
452
+ @driver.should_become [105, 95, 0]
453
+ end
454
+
455
+ it "should be able to fade from current colour to a new colour" do
456
+ @light.go [100, 100, 0]
457
+ @driver.should_become [100, 100, 0]
458
+
459
+ @light.fade_to([105, 95, 0], 5, 2)
460
+ @driver.should_become [101, 99, 0]
461
+ @driver.should_become [102, 98, 0]
462
+ @driver.should_become [103, 97, 0]
463
+ @driver.should_become [104, 96, 0]
464
+ @driver.should_become [105, 95, 0]
465
+ end
466
+
467
+ it "should be able to go different colours based on a function" do
468
+ cycle = [:blue, :red, :green, :purple, :grey, :aqua].cycle
469
+ @light.func(10) { cycle.next }
470
+ @driver.should_become :blue
471
+ @driver.should_become :red
472
+ @driver.should_become :green
473
+ @driver.should_become :purple
474
+ @driver.should_become :grey
475
+ @driver.should_become :aqua
476
+ end
109
477
  end
110
478
  end
111
479
 
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
2
  $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'support'))
3
4
  require 'rspec'
4
5
  require 'cheeky-dreams'
5
6
 
@@ -0,0 +1,18 @@
1
+
2
+
3
+ class CollectingAuditor
4
+
5
+ attr_reader :errors
6
+
7
+ def initialize
8
+ @errors = []
9
+ end
10
+
11
+ def unhandled_error e
12
+ @errors << e
13
+ end
14
+
15
+ def has_received? e
16
+ @errors.include? e
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ require 'within'
2
+
3
+ class StubDriver
4
+
5
+ include Within
6
+
7
+ def initialize
8
+ @lock = Mutex.new
9
+ @colours = []
10
+ end
11
+
12
+ def go colour
13
+ @lock.synchronize {
14
+ @colour = colour
15
+ @colours << colour
16
+ }
17
+ end
18
+
19
+ def should_become expected_colour
20
+ rgb = expected_colour.is_a?(Symbol) ? CheekyDreams::COLOURS[expected_colour] : expected_colour
21
+ within 1, "driver to become #{rgb}" do
22
+ @lock.synchronize {
23
+ [rgb == @colour, @colour]
24
+ }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+
2
+ class StubEffect < CheekyDreams::Effect::Effect
3
+
4
+ attr_reader :freq, :asked_for_colour_count
5
+
6
+ def initialize freq, &block
7
+ @freq, @asked_for_colour_count = freq, 0
8
+ if block
9
+ @block = block
10
+ else
11
+ @block = lambda { [0,0,0] }
12
+ end
13
+ end
14
+
15
+ def next last_colour
16
+ @asked_for_colour_count += 1
17
+ @block.yield
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ module Within
2
+ def within seconds, what
3
+ raise 'errm, was expected a block to perform condition on' unless block_given?
4
+ start, match, hint = Time.now, false, "[you didnt specify]"
5
+ while (((Time.now - start) < seconds) && !match) do
6
+ match, hint = yield
7
+ end
8
+ raise "Expected #{what}, within #{seconds} second, instead was #{hint}" unless match
9
+ end
10
+ end
data/spec/test.rb CHANGED
@@ -7,8 +7,15 @@ require 'rainbow'
7
7
 
8
8
  include CheekyDreams
9
9
 
10
- light = Light.new(ansi_driver, 10)
11
- light.on
10
+ light = Light.new find_dream_cheeky_usb_device
11
+
12
+ puts "throbbing"
13
+ light.throb(2, [255,0,0],[0, 255, 0])
14
+ sleep 10
15
+
16
+ puts "is it red"
17
+ light.go [255,0,0]
18
+ sleep 1
12
19
 
13
20
  puts "colours"
14
21
  [:red, :green, :blue, CheekyDreams::rgb(155, 155, 155)].each do |colour|
@@ -17,25 +24,31 @@ puts "colours"
17
24
  end
18
25
 
19
26
  puts "cycle"
20
- light.go(cycle(CheekyDreams::COLOURS.keys, 2))
27
+ light.cycle(CheekyDreams::COLOURS.keys, 2)
21
28
  sleep 5
22
29
 
23
30
  puts "fade"
24
- light.go(fade(:green, :red, 2))
31
+ light.fade(:green, :red, 20, 2)
25
32
  sleep 3
26
- light.go(fade(:red, :green, 2))
33
+ light.fade(:red, :green, 20, 2)
27
34
  sleep 3
28
35
 
29
36
  puts "fade from current to somewhere"
37
+ light.go :red
38
+ sleep 2
39
+ light.fade_to :green, 20, 2
40
+ sleep 2
41
+ light.fade_to :red, 20, 2
42
+ sleep 2
30
43
 
31
44
  puts "colour on block"
32
45
  cycle = [:blue, :purple].cycle
33
- light.go(func(2) { cycle.next })
46
+ light.func(2) { cycle.next }
34
47
  sleep 3
35
48
 
36
49
  puts "fake cpu cycles"
37
50
  green = 100
38
- light.go(func(2) { [0, green+=20, 0] })
51
+ light.func(2) { [0, green+=20, 0] }
39
52
  sleep 3
40
53
 
41
54
  puts "done"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cheeky-dreams
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,22 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-28 00:00:00.000000000Z
12
+ date: 2011-11-02 00:00:00.000000000Z
13
13
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: flt
16
- requirement: &2158506720 !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: 1.3.0
22
- type: :runtime
23
- prerelease: false
24
- version_requirements: *2158506720
25
14
  - !ruby/object:Gem::Dependency
26
15
  name: rspec
27
- requirement: &2158503320 !ruby/object:Gem::Requirement
16
+ requirement: &2168510760 !ruby/object:Gem::Requirement
28
17
  none: false
29
18
  requirements:
30
19
  - - ! '>='
@@ -32,10 +21,10 @@ dependencies:
32
21
  version: 2.3.0
33
22
  type: :development
34
23
  prerelease: false
35
- version_requirements: *2158503320
24
+ version_requirements: *2168510760
36
25
  - !ruby/object:Gem::Dependency
37
26
  name: bundler
38
- requirement: &2158502820 !ruby/object:Gem::Requirement
27
+ requirement: &2168510280 !ruby/object:Gem::Requirement
39
28
  none: false
40
29
  requirements:
41
30
  - - ~>
@@ -43,10 +32,10 @@ dependencies:
43
32
  version: 1.0.0
44
33
  type: :development
45
34
  prerelease: false
46
- version_requirements: *2158502820
35
+ version_requirements: *2168510280
47
36
  - !ruby/object:Gem::Dependency
48
37
  name: jeweler
49
- requirement: &2158502260 !ruby/object:Gem::Requirement
38
+ requirement: &2168509720 !ruby/object:Gem::Requirement
50
39
  none: false
51
40
  requirements:
52
41
  - - ~>
@@ -54,10 +43,10 @@ dependencies:
54
43
  version: 1.6.4
55
44
  type: :development
56
45
  prerelease: false
57
- version_requirements: *2158502260
46
+ version_requirements: *2168509720
58
47
  - !ruby/object:Gem::Dependency
59
48
  name: rcov
60
- requirement: &2158501660 !ruby/object:Gem::Requirement
49
+ requirement: &2160044460 !ruby/object:Gem::Requirement
61
50
  none: false
62
51
  requirements:
63
52
  - - ! '>='
@@ -65,7 +54,7 @@ dependencies:
65
54
  version: '0'
66
55
  type: :development
67
56
  prerelease: false
68
- version_requirements: *2158501660
57
+ version_requirements: *2160044460
69
58
  description: For controlling dream cheeky usb light
70
59
  email: simojenki@gmail.com
71
60
  executables: []
@@ -82,9 +71,14 @@ files:
82
71
  - README.rdoc
83
72
  - Rakefile
84
73
  - VERSION
74
+ - cheeky-dreams.gemspec
85
75
  - lib/cheeky-dreams.rb
86
76
  - spec/cheeky-dreams_spec.rb
87
77
  - spec/spec_helper.rb
78
+ - spec/support/collecting_auditor.rb
79
+ - spec/support/stub_driver.rb
80
+ - spec/support/stub_effect.rb
81
+ - spec/support/within.rb
88
82
  - spec/test.rb
89
83
  homepage: http://github.com/simojenki/cheeky-dreams
90
84
  licenses:
@@ -101,7 +95,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
101
95
  version: '0'
102
96
  segments:
103
97
  - 0
104
- hash: 1122224430567929941
98
+ hash: -1596020986901995182
105
99
  required_rubygems_version: !ruby/object:Gem::Requirement
106
100
  none: false
107
101
  requirements: