rustle 0.1.1 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a832c77bff50413388dc4b5e7930c623a8807c5e
4
- data.tar.gz: 4565b1dfd7ed5ddae95fe044b3419a3dfa850224
3
+ metadata.gz: 5471958598d61f4dc25f459bdad141ada82b1bd0
4
+ data.tar.gz: 9f0f17ec4a82206000b729e697bffd7778848d68
5
5
  SHA512:
6
- metadata.gz: ab2b36845325b8f6ad07c9c78ffbb83c6372b7c167c213d1444ffb1f3c9c18c7ba0fb42f5726c023a04cc2384b450ccf5596129764d41741a0d402bcf56a4774
7
- data.tar.gz: 5eeea99ff6e98b0e7d310aa55f5a0b603a5feffa132dc915d6e2d2870c820dd8cc4a010aea53cdfd53a64d1e3dae4cb6f37106573e98d91cf0900a7c8b92bf32
6
+ metadata.gz: 6744cbf1557218443148fc94c02f3728af062d97320202323d234e2251415a8696fb2369b2ec9d9401519e4cb5250b621a8a982ff153337f8f317847b6e240b7
7
+ data.tar.gz: 41a86f55fa7681a319da9853a3dcd3c06aa392daeac3cc91dadbb5cada709ae7a298e6c4d90e6dd3e4e5850b6907a45c45229b13aceb2314fc4f33bab1648368
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Rustle Changelog
2
2
 
3
+ ## 0.1.2
4
+
5
+ #### New
6
+
7
+ * Much more spec coverage.
8
+ * Invalid data handling
9
+ * **Debug mode**: to make specs easier, Receiver objects can be set to debug mode, in which no actual data will be sent to the Arduino, and instead will be returned as arrays.
10
+
11
+ #### Deprecated
12
+
13
+ * The old DSL-style Receiver instantiation syntax. See the documentation for Receiver#initialize because the syntax is now quite different.
14
+
3
15
  ## 0.1.1
4
16
 
5
17
  #### New
@@ -0,0 +1,18 @@
1
+ module Rustle
2
+ # = DebugPort
3
+ #
4
+ # This class's purpose is simply to provide a mock serial port for debugging
5
+ # purposes. Instead of writing to an actual TTY connection, it simply
6
+ # deserializes and returns the values passed into it. It's convenient because
7
+ # it allows one to test without requiring a physical Arduino.
8
+ class DebugPort
9
+ # @param [String] string the string of chars to be written to the mock
10
+ # serial port
11
+ #
12
+ # @return [Array<Fixnum>] an array containing the deserialized values found
13
+ # in +string+
14
+ def write(string)
15
+ string.chars.map(&:ord)
16
+ end
17
+ end
18
+ end
@@ -7,4 +7,13 @@ module Rustle
7
7
 
8
8
  # Raised when a user provides an invalid hexadecimal color
9
9
  class InvalidHexColorCode < Error; end
10
+
11
+ # Raised when a user does not provide a receiver when instantiating a strip
12
+ class ReceiverNotFound < Error; end
13
+
14
+ # Raised when a user does not specify the number of LEDs for a strip
15
+ class NumLEDsInvalid < Error; end
16
+
17
+ # Raised when a user tries to provide data that is not an array of {Color} objects
18
+ class InvalidLEDArray < Error; end
10
19
  end
data/lib/rustle/frame.rb CHANGED
@@ -28,6 +28,8 @@ module Rustle
28
28
  # @param [Array] leds n array of {Color} objects, whose length is the same
29
29
  # as the number of LEDs connected to the strip.
30
30
  def initialize(leds)
31
+ validate_leds(leds)
32
+
31
33
  @leds = leds
32
34
  end
33
35
 
@@ -38,5 +40,11 @@ module Rustle
38
40
  def serialize
39
41
  @leds.map(&:serialize).join + 255.chr
40
42
  end
43
+
44
+ private
45
+
46
+ def validate_leds(arr)
47
+ raise InvalidLEDArray unless arr.all? { |l| l.is_a? Color }
48
+ end
41
49
  end
42
50
  end
@@ -11,10 +11,7 @@ module Rustle
11
11
  #
12
12
  # The Receiver class is initialized using a block.
13
13
  #
14
- # bedroom_arduino = Rustle::Receiver.new do
15
- # port_file "/dev/[PORT_FILE]"
16
- # num_leds 30
17
- # end
14
+ # bedroom_arduino = Rustle::Receiver.new("/dev/[PORT_FILE]")
18
15
  #
19
16
  # Your port file can be found using the Arduino IDE.
20
17
  class Receiver
@@ -23,29 +20,33 @@ module Rustle
23
20
  # @return [Strip] the strip associated with the Receiver
24
21
  attr_reader :strip
25
22
 
26
- # Initializes a new receiver.
23
+ # Initializes a new receiver.
27
24
  #
28
25
  # @example
29
- # kitchen_arduino = Rustle::Receiver.new do
30
- # port_file "/dev/tty.usbmodem411" # replace this
31
- # num_leds 60
32
- # end
26
+ # kitchen_arduino = Rustle::Receiver.new("/deb/tty.usbmodem411",
27
+ # num_leds: 30, baud: 921_600, debug: false)
33
28
  #
34
- # @yieldparam [String] port_file the location of serial port file. It can be
29
+ # @param [String] port_file the location of serial port file. It can be
35
30
  # found in the Arduino IDE (or via Ino).
36
- # @yieldparam [Fixnum] baud (optional) the serial baud rate (make sure it matches the one in
31
+ # @param [Fixnum] baud the serial baud rate (make sure it matches the one in
37
32
  # your sketch)
38
- # @yieldparam [Fixnum] num_leds (optional) the total number of LEDs connected to your
33
+ # @param [Fixnum] num_leds the total number of LEDs connected to your
39
34
  # receiver. Note that this attribute only affects how the {Strip} object
40
35
  # is instantiated; the number of LEDs is not actually stored in the
41
36
  # Receiver object.
42
- def initialize(&block)
43
- # Default value
44
- @baud = 921_600
45
-
46
- instance_eval &block
37
+ # @param [Boolean] debug whether or not to enable debug mode. See
38
+ # {DebugPort}.
39
+ def initialize(port_file = nil, baud: 921_600, num_leds: 30, debug: false)
40
+ @port_file = port_file
41
+ @baud = baud
42
+ @debug = debug
43
+ @strip = Strip.new(self, num_leds)
47
44
 
48
45
  init_serialport
46
+
47
+ # Sending a blank frame upon initialization seems to fix all timing
48
+ # constraint problems.
49
+ @strip.off!
49
50
  end
50
51
 
51
52
  # Serializes +frame+ and sends it off to the the serial port. +push_frame+
@@ -58,16 +59,14 @@ module Rustle
58
59
 
59
60
  private
60
61
 
61
- # instance_eval-specific methods for our DSL
62
- def port_file(file); @port_file = file; end
63
- def baud(int); @baud = int; end
64
- def num_leds(count)
65
- @strip = Strip.new(self, count)
66
- end
67
-
68
- # Instantiates a new serial port
62
+ # Instantiates a new port
69
63
  def init_serialport
70
- @port = SerialPort.new @port_file, @baud, 8, 1, SerialPort::NONE
64
+ if @debug
65
+ @port = DebugPort.new
66
+ else
67
+ raise PortFileNotSpecified if @debug == false
68
+ @port = SerialPort.new @port_file, @baud, 8, 1, SerialPort::NONE
69
+ end
71
70
  end
72
71
  end
73
72
  end
data/lib/rustle/strip.rb CHANGED
@@ -3,7 +3,7 @@ require 'active_support/inflector'
3
3
  module Rustle
4
4
  # = Strips
5
5
  #
6
- # The Strip class' purpose is to respond to requests to change the color of
6
+ # The Strip class's purpose is to respond to requests to change the color of
7
7
  # the physical strip, and send changes to the {Receiver} when appropriate.
8
8
  # All Strip objects also have a buffer, which is simply an array of {Frame}
9
9
  # objects. Calling any method which advances to the next frame causes the
@@ -27,6 +27,9 @@ module Rustle
27
27
  @receiver = receiver
28
28
  @num_leds = num_leds
29
29
  @queue = []
30
+
31
+ raise ReceiverNotFound unless receiver.is_a? Receiver
32
+ raise NumLEDsInvalid unless @num_leds && @num_leds > 0
30
33
  end
31
34
 
32
35
  # @return [Frame] the next frame in the buffer. If the buffer only has one
@@ -56,6 +59,7 @@ module Rustle
56
59
 
57
60
  # Turns off all LEDs on the strip
58
61
  def off!
62
+ sleep 0.0025
59
63
  @queue << Frame.new([Color.new(0,0,0)] * @num_leds)
60
64
  next_frame!
61
65
  end
@@ -64,6 +68,7 @@ module Rustle
64
68
  #
65
69
  # @param [Color] color
66
70
  def to(color)
71
+ sleep 0.0025
67
72
  @queue << Frame.new([color] * @num_leds)
68
73
  next_frame!
69
74
  end
@@ -89,7 +94,7 @@ module Rustle
89
94
  # :fade_to => FadeToTransition
90
95
  klass = "#{klass.to_s.camelize}Transition".constantize
91
96
 
92
- klass.new(self, duration, opts).frames
97
+ klass.new(self, duration, opts)
93
98
  end
94
99
  end
95
100
  end
@@ -1,3 +1,3 @@
1
1
  module Rustle
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
data/lib/rustle.rb CHANGED
@@ -4,10 +4,13 @@ require "rustle/receiver"
4
4
  require "rustle/strip"
5
5
  require "rustle/color"
6
6
  require "rustle/frame"
7
+
7
8
  require "rustle/transition"
8
9
  require "rustle/transitions/wipe_to_transition"
9
10
  require "rustle/transitions/fade_to_transition"
11
+
10
12
  require "rustle/exceptions"
13
+ require "rustle/debug_port"
11
14
 
12
15
  module Rustle
13
16
  FRAME_RATE = 60
data/spec/color_spec.rb CHANGED
@@ -8,49 +8,38 @@ describe Rustle::Color do
8
8
  let(:color_with_invalid_params) { Rustle::Color.new(-100,1000,0) }
9
9
 
10
10
  it "corrects negative rgb values to zero" do
11
- (color_with_invalid_params.r).should eq(0)
11
+ expect(color_with_invalid_params.r).to eq(0)
12
12
  end
13
13
 
14
14
  it "corrects very large rgb values to 255" do
15
- (color_with_invalid_params.g).should eq(255)
15
+ expect(color_with_invalid_params.g).to eq(255)
16
16
  end
17
17
 
18
18
  it "makes no changes to rgb values between 0 and 255" do
19
19
  color1 = Rustle::Color.new(0,0,0)
20
- (color1.r).should eq(0)
21
- (color1.g).should eq(0)
22
- (color1.b).should eq(0)
20
+ expect(color1.r).to eq(0)
21
+ expect(color1.g).to eq(0)
22
+ expect(color1.b).to eq(0)
23
23
 
24
24
  color2 = Rustle::Color.new(255,255,255)
25
- (color2.r).should eq(255)
26
- (color2.g).should eq(255)
27
- (color2.b).should eq(255)
25
+ expect(color2.r).to eq(255)
26
+ expect(color2.g).to eq(255)
27
+ expect(color2.b).to eq(255)
28
28
  end
29
29
  end
30
30
 
31
31
  describe "#to_a" do
32
32
  it "returns an array" do
33
- (color.to_a).should be_a(Array)
33
+ expect(color.to_a).to be_a(Array)
34
34
  end
35
35
 
36
36
  it "the array has the correct [r,g,b] values" do
37
- (color.to_a).should eq([128,128,128])
37
+ expect(color.to_a).to eq([128,128,128])
38
38
  end
39
39
 
40
40
  it "rounds decimal values down to the nearest whole number" do
41
41
  fractional_rgbs = Rustle::Color.rgb(0.5,10.7,99.9)
42
- (fractional_rgbs.to_a).should eq([0, 10, 99])
43
- end
44
- end
45
-
46
- describe "#to_s" do
47
- it "returns a string with information about the color" do
48
- (color.to_s).should eq("rgb(128, 128, 128)")
49
- end
50
-
51
- it "pads strings so that even small rgb values align properly" do
52
- other_color = Rustle::Color.rgb(0,1,2)
53
- (other_color.to_s).should eq("rgb( 0, 1, 2)")
42
+ expect(fractional_rgbs.to_a).to eq([0, 10, 99])
54
43
  end
55
44
  end
56
45
 
@@ -60,11 +49,11 @@ describe Rustle::Color do
60
49
  let(:colorB) { Rustle::Color.rgb(0, 0, 0) }
61
50
 
62
51
  it "returns true if the reciever and parameter objects hold equivalent rgb values" do
63
- (colorA.eql?(another_colorA)).should be_true
52
+ expect(colorA.eql?(another_colorA)).to be_true
64
53
  end
65
54
 
66
55
  it "returns false if the reciever and parameter objects differ in rgb values" do
67
- (colorA.eql?(colorB)).should be_false
56
+ expect(colorA.eql?(colorB)).to be_false
68
57
  end
69
58
  end
70
59
 
@@ -75,11 +64,11 @@ describe Rustle::Color do
75
64
  let (:badass) { Rustle::Color.hex "BADA55" }
76
65
 
77
66
  it "creates a color object" do
78
- (badass).should be_a(Rustle::Color)
67
+ expect(badass).to be_a(Rustle::Color)
79
68
  end
80
69
 
81
70
  it "has the proper rgb values" do
82
- (badass).should eql(badass_rgb)
71
+ expect(badass).to eql(badass_rgb)
83
72
  end
84
73
  end
85
74
 
@@ -87,11 +76,11 @@ describe Rustle::Color do
87
76
  let(:badass) { Rustle::Color.hex "#BADA55" }
88
77
 
89
78
  it "creates a color object" do
90
- (badass).should be_a(Rustle::Color)
79
+ expect(badass).to be_a(Rustle::Color)
91
80
  end
92
81
 
93
82
  it "has the right rgb values" do
94
- (badass).should eql(badass_rgb)
83
+ expect(badass).to eql(badass_rgb)
95
84
  end
96
85
  end
97
86
 
@@ -100,18 +89,18 @@ describe Rustle::Color do
100
89
  let(:bad_rgb) { Rustle::Color.rgb 187, 170, 221 }
101
90
 
102
91
  it "creates a color object" do
103
- (bad_hex).should be_a(Rustle::Color)
92
+ expect(bad_hex).to be_a(Rustle::Color)
104
93
  end
105
94
 
106
95
  it "should have the correct rgb values" do
107
- (bad_hex).should eql(bad_rgb)
96
+ expect(bad_hex).to eql(bad_rgb)
108
97
  end
109
98
  end
110
99
 
111
100
  it "is case insensitive" do
112
101
  first_badass = Rustle::Color.hex "#BADa55"
113
102
  second_badass = Rustle::Color.hex "#badA55"
114
- (first_badass).should eql(second_badass)
103
+ expect(first_badass).to eql(second_badass)
115
104
  end
116
105
 
117
106
  it "raises an error when given an invalid color code string" do
@@ -127,14 +116,14 @@ describe Rustle::Color do
127
116
  # HSV: 260 (260), saturation: 23 (23.0769), value: 87 (86.6667)
128
117
 
129
118
  it "produces a color object" do
130
- hsb.should be_a(Rustle::Color)
119
+ expect(hsb).to be_a(Rustle::Color)
131
120
  end
132
121
 
133
122
  it "has the correct rgb properties" do
134
123
  # Use be_within to give some allowance for rounting errors
135
- (hsb.r).should be_within(3).of(rgb.r)
136
- (hsb.g).should be_within(3).of(rgb.g)
137
- (hsb.b).should be_within(3).of(rgb.b)
124
+ expect(hsb.r).to be_within(3).of(rgb.r)
125
+ expect(hsb.g).to be_within(3).of(rgb.g)
126
+ expect(hsb.b).to be_within(3).of(rgb.b)
138
127
  end
139
128
  end
140
129
 
@@ -142,14 +131,14 @@ describe Rustle::Color do
142
131
  let(:hsb) { Rustle::Color.hsb 180, 0.5, 0.8 }
143
132
 
144
133
  it "returns an array of [h,s,v] coordinates" do
145
- color.to_hsb.should be_a(Array)
134
+ expect(color.to_hsb).to be_a(Array)
146
135
  end
147
136
 
148
137
  it "should have the (approximate) [h,s,v] coordinates" do
149
138
  hsb_arr = hsb.to_hsb
150
- hsb_arr[0].should be_within(1).of(180)
151
- hsb_arr[1].should be_within(0.1).of(0.5)
152
- hsb_arr[2].should be_within(0.1).of(0.8)
139
+ expect(hsb_arr[0]).to be_within(1).of(180)
140
+ expect(hsb_arr[1]).to be_within(0.1).of(0.5)
141
+ expect(hsb_arr[2]).to be_within(0.1).of(0.8)
153
142
  end
154
143
 
155
144
  end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rustle::Frame do
4
+ describe "initialization" do
5
+ it "should require a valid array of LEDs" do
6
+ valid = [Rustle::Color.rgb(255, 0, 0)] * 5
7
+ invalid = ["poop"] * 5
8
+
9
+ expect { Rustle::Frame.new(invalid) }
10
+ .to raise_error(Rustle::InvalidLEDArray)
11
+
12
+ expect { Rustle::Frame.new(valid) }
13
+ .not_to raise_error
14
+ end
15
+ end
16
+ end
@@ -1,5 +1,32 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Rustle::Receiver do
4
- it "does nothing"
4
+ describe "#initialize" do
5
+ let(:receiver) do
6
+ Rustle::Receiver.new(nil, num_leds: 30, debug: true)
7
+ end
8
+
9
+ it "should intantiate a Strip with the appropriate number of LEDs" do
10
+ expect(receiver.strip).to be_a(Rustle::Strip)
11
+ expect(receiver.strip.num_leds).to eq(30)
12
+ end
13
+
14
+ it "should only require a portfile when not in debug mode" do
15
+ expect { Rustle::Receiver.new(nil, debug: false) }
16
+ .to raise_error(Rustle::PortFileNotSpecified)
17
+ expect { Rustle::Receiver.new(nil, debug: true) }
18
+ .not_to raise_error
19
+ end
20
+ end
21
+
22
+ describe "#push_frame" do
23
+ let(:receiver) do
24
+ Rustle::Receiver.new(nil, num_leds: 30, debug: true)
25
+ end
26
+
27
+ it "should send a frame to the port" do
28
+ frame = Rustle::Frame.new([Rustle::Color.new(0,0,0)] * 30)
29
+ expect(receiver.push_frame(frame)).to have(91).items
30
+ end
31
+ end
5
32
  end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rustle::Strip do
4
+ context "when initializing" do
5
+ it "should require a receiver" do
6
+ expect { Rustle::Strip.new(nil, 30) }.to raise_error(Rustle::ReceiverNotFound)
7
+ end
8
+
9
+ it "should require an LED count" do
10
+ receiver = Rustle::Receiver.new(nil, debug: true)
11
+ expect { Rustle::Strip.new(receiver, nil) }.to raise_error(Rustle::NumLEDsInvalid)
12
+ end
13
+ end
14
+
15
+ describe "queue" do
16
+ let(:strip) { Rustle::Receiver.new(nil, num_leds: 5, debug: true).strip }
17
+
18
+ it "should be initialized with a black frame" do
19
+ expect(strip.current_frame).to_not be_nil
20
+ end
21
+
22
+ it "should be initialized with a black frame" do
23
+ frame = Rustle::Frame.new [Rustle::Color.new(255, 0, 0)] * 5
24
+
25
+ strip.queue_frames [frame]
26
+ expect(strip.next_frame).to_not be_nil
27
+
28
+ # After advancing to the next frame, there shouldn't be a next_frame
29
+ strip.next_frame!
30
+ expect(strip.next_frame).to eq(strip.current_frame)
31
+ end
32
+ end
33
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rustle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Hamon
@@ -117,6 +117,7 @@ files:
117
117
  - Rakefile
118
118
  - lib/rustle.rb
119
119
  - lib/rustle/color.rb
120
+ - lib/rustle/debug_port.rb
120
121
  - lib/rustle/exceptions.rb
121
122
  - lib/rustle/frame.rb
122
123
  - lib/rustle/receiver.rb
@@ -129,8 +130,10 @@ files:
129
130
  - rustle_logo.png
130
131
  - sketches/basic.ino
131
132
  - spec/color_spec.rb
133
+ - spec/frame_spec.rb
132
134
  - spec/receiver_spec.rb
133
135
  - spec/spec_helper.rb
136
+ - spec/strip_spec.rb
134
137
  homepage: ''
135
138
  licenses:
136
139
  - MIT
@@ -158,6 +161,8 @@ specification_version: 4
158
161
  summary: Control an individually-addressable RGB LED strip in Ruby.
159
162
  test_files:
160
163
  - spec/color_spec.rb
164
+ - spec/frame_spec.rb
161
165
  - spec/receiver_spec.rb
162
166
  - spec/spec_helper.rb
167
+ - spec/strip_spec.rb
163
168
  has_rdoc: