brewby-cli 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a730c58cd6decfcabe608df7bfc0d01634ab1c10
4
+ data.tar.gz: 724b8d2e0034ea369f119474dec401e1eb9dba12
5
+ SHA512:
6
+ metadata.gz: 8b0657a1ae18d35cf2be935ef5edec1ddefdca5a6b517414968e9e04101eadf7a2278647b150120246a00453ca743d6e66393cc2ea7ff1afbfc8bda0eca5242e
7
+ data.tar.gz: 07715b81743ed36187d42be9a89099483f2eef694385f816ac590fbc22f5e864feba61be0352b57d0b5acd9e936993ae34ecfb9ff519739df7373858fa480cfb
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_BIN: bin
@@ -0,0 +1 @@
1
+ bin
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,45 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ brewby-cli (0.1.0)
5
+ brewby (~> 0.1.1)
6
+ ffi-ncurses
7
+ thor
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ brewby (0.1.1)
13
+ temper-control
14
+ coderay (1.1.0)
15
+ diff-lcs (1.2.5)
16
+ ffi (1.9.3)
17
+ ffi-locale (1.0.1)
18
+ ffi (>= 1.0.9)
19
+ ffi-ncurses (0.4.0)
20
+ ffi (>= 1.0.9)
21
+ ffi-locale (>= 1.0.0)
22
+ method_source (0.8.2)
23
+ pry (0.9.12.6)
24
+ coderay (~> 1.0)
25
+ method_source (~> 0.8)
26
+ slop (~> 3.4)
27
+ rspec (2.14.1)
28
+ rspec-core (~> 2.14.0)
29
+ rspec-expectations (~> 2.14.0)
30
+ rspec-mocks (~> 2.14.0)
31
+ rspec-core (2.14.7)
32
+ rspec-expectations (2.14.4)
33
+ diff-lcs (>= 1.1.3, < 2.0)
34
+ rspec-mocks (2.14.4)
35
+ slop (3.4.7)
36
+ temper-control (0.0.1)
37
+ thor (0.18.1)
38
+
39
+ PLATFORMS
40
+ ruby
41
+
42
+ DEPENDENCIES
43
+ brewby-cli!
44
+ pry
45
+ rspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Andrew Nordman
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
1
+ # brewby-cli
2
+
3
+ An ncurses-based terminal application for the Brewby ecosystem.
4
+
5
+ ![screenshot](http://f.cl.ly/items/301C0o071J0y0i010x1v/cli-screenshot.png)
6
+
7
+ ## Install
8
+
9
+ Brewby CLI is released as a gem on rubygems. `gem install brewby-cli`
10
+
11
+ ## Usage
12
+
13
+ Brewby CLI currently responds to the 'start' command only. When run by itself, it loads your
14
+ equipment configuration and begins a `TempControl` step in manual power mode at 0% power.
15
+
16
+ When passing a Brewby Recipe file via `--recipe FILE`, it loads the equipment configuration, parses the recipe file,
17
+ and starts the first step in the recipe.
18
+
19
+ By default, Brewby CLI looks for an equipment configuration file at `~/.brewbyrc`, detailing the
20
+ IO adapters and names. These names map to the recipe file. To specify a different file for
21
+ equipment loading, pass the `--config CONFIG` flag.
22
+
@@ -0,0 +1,7 @@
1
+ require 'rspec/core/rake_task'
2
+ require "bundler/gem_tasks"
3
+ require 'bundler/setup'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ Gem::Specification.new do |gem|
3
+ gem.authors = ["Andrew Nordman"]
4
+ gem.email = ["cadwallion@gmail.com"]
5
+ gem.summary = %q{An ncurses-based terminal application for the Brewby ecosystem}
6
+ gem.homepage = ""
7
+
8
+ gem.files = `git ls-files`.split($\)
9
+ gem.executables = ['brewby']
10
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
11
+ gem.name = "brewby-cli"
12
+ gem.require_paths = ["lib"]
13
+ gem.version = "0.1.0"
14
+
15
+ gem.add_development_dependency 'rspec'
16
+ gem.add_development_dependency 'pry'
17
+ gem.add_dependency 'thor'
18
+ gem.add_dependency 'ffi-ncurses'
19
+ gem.add_dependency 'brewby', '~>0.1.1'
20
+ end
@@ -0,0 +1,35 @@
1
+ recipe 'Honey Ale' do
2
+ step 'Strike Water' do
3
+ type :temp_control
4
+ mode :auto
5
+ target 168.0
6
+ hold_duration 5
7
+ input :hlt
8
+ output :hlt
9
+ end
10
+
11
+ step 'Infusion Mash Step' do
12
+ type :temp_control
13
+ mode :auto
14
+ target 150.0
15
+ hold_duration 60
16
+ input :mlt
17
+ output :hlt
18
+ end
19
+
20
+ step 'Fly Sparge' do
21
+ type :temp_control
22
+ mode :auto
23
+ target 168.0
24
+ hold_duration 45
25
+ input :hlt
26
+ output :hlt
27
+ end
28
+
29
+ step 'Boil' do
30
+ type :temp_control
31
+ mode :manual
32
+ input :bk
33
+ output :bk
34
+ end
35
+ end
@@ -0,0 +1,12 @@
1
+ {
2
+ "adapter":"raspberry_pi",
3
+ "inputs":[
4
+ { "name":"mlt", "hardware_id":"28-12345" },
5
+ { "name":"hlt", "hardware_id":"28-67891" },
6
+ { "name":"bk", "hardware_id":"28-01983" }
7
+ ],
8
+ "outputs":[
9
+ { "pin":17, "name":"hlt" },
10
+ { "pin":19, "name": "bk" }
11
+ ]
12
+ }
@@ -0,0 +1,2 @@
1
+ require 'brewby/cli/application'
2
+ require 'brewby/cli/view'
@@ -0,0 +1,36 @@
1
+ require 'brewby'
2
+ require 'brewby/cli/views/application'
3
+
4
+ module Brewby
5
+ module CLI
6
+ class Application < Brewby::Application
7
+ attr_accessor :ready
8
+ attr_reader :view
9
+ def initialize options = {}
10
+ super
11
+ configure_view
12
+ end
13
+
14
+ def configure_view
15
+ @view = Brewby::CLI::Views::Application.new self
16
+ end
17
+
18
+ def start
19
+ super
20
+ ensure
21
+ view.clear if view
22
+ end
23
+
24
+ def start_step step
25
+ super
26
+ view.load_step_view step
27
+ end
28
+
29
+ def tick
30
+ super
31
+ view.render
32
+ view.handle_input
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ require 'ffi-ncurses'
2
+ require 'brewby/cli/views/application'
3
+ require 'brewby/cli/views/temp_control'
4
+
5
+ module Brewby
6
+ module CLI
7
+ class View
8
+ include FFI::NCurses
9
+
10
+ def initialize
11
+ initscr
12
+ cbreak
13
+ noecho
14
+ timeout(100)
15
+ curs_set 0
16
+ counter = 0
17
+ end
18
+
19
+ def clear
20
+ endwin
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,63 @@
1
+ require 'brewby/cli/view'
2
+
3
+ module Brewby
4
+ module CLI
5
+ module Views
6
+ class Application
7
+ attr_reader :view, :step_view, :app
8
+ def initialize app
9
+ @app = app
10
+ @view = load_parent_view
11
+ end
12
+
13
+ def load_parent_view
14
+ Brewby::CLI::View.new
15
+ end
16
+
17
+ def current_step_index
18
+ app.steps.index(app.current_step)+1
19
+ end
20
+
21
+ def step_count
22
+ app.steps.size
23
+ end
24
+
25
+ def brew_timer
26
+ app.timer_for(app.elapsed.to_i)
27
+ end
28
+
29
+ def render
30
+ load_step_view app.current_step unless step_view
31
+ view.move 1, 0
32
+ view.addstr "BREWBY: Brewing '#{app.name}'" if app.name
33
+ view.move 2, 0
34
+ view.addstr "Step #{current_step_index}/#{step_count}: "
35
+ view.move 16, 0
36
+ view.addstr "Brew Timer: #{brew_timer}"
37
+ view.refresh
38
+ step_view.render
39
+ end
40
+
41
+ def handle_input
42
+ if (char = view.getch) == 'q'[0].ord
43
+ exit
44
+ elsif char == 'n'[0].ord
45
+ app.current_step.stop_timer
46
+ app.ready = true
47
+ else
48
+ step_view.handle_input char
49
+ end
50
+ end
51
+
52
+ def load_step_view step
53
+ step_class_name = step.class.name.split("::").last
54
+ @step_view = Brewby::CLI::Views.const_get(step_class_name).new step, view
55
+ end
56
+
57
+ def clear
58
+ view.clear
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,71 @@
1
+ module Brewby
2
+ module CLI
3
+ module Views
4
+ class TempControl
5
+ attr_reader :step, :view
6
+ def initialize step, view
7
+ @step = step
8
+ @view = view
9
+ end
10
+
11
+ def power_level
12
+ (step.power_level * 100.0).round(3)
13
+ end
14
+
15
+ def timer
16
+ step.timer_for(step.elapsed.to_i)
17
+ end
18
+
19
+ def time_remaining
20
+ step.countdown_for(step.time_remaining)
21
+ end
22
+
23
+ def render
24
+ view.move 2, 10
25
+ if step.name
26
+ view.addstr step.name.ljust(70)
27
+ else
28
+ view.addstr "#{step.mode.capitalize} Temp Control".ljust(70)
29
+ end
30
+
31
+ view.move 6, 0
32
+ view.addstr "Power Level: #{power_level}%".ljust(70)
33
+ view.move 16, 50
34
+ view.addstr "Step Timer: #{timer}"
35
+ view.refresh
36
+
37
+ if step.target
38
+ view.move 4, 0
39
+ view.addstr "Target Temp: #{step.target} F".ljust(70)
40
+ end
41
+
42
+ view.move 5, 0
43
+ view.addstr "Actual Temp: #{step.last_reading} F".ljust(25)
44
+
45
+ if step.threshold_reached
46
+ view.move 7, 0
47
+ view.addstr "Time Remaining: #{time_remaining}".ljust(70)
48
+ else
49
+ view.move 7, 0
50
+ view.addstr "".ljust(70)
51
+ end
52
+ end
53
+
54
+ def handle_input key
55
+ case key
56
+ when 'e'.ord
57
+ if step.mode == :manual
58
+ new_pct = [(step.power_level + 0.05).round(2), 1.0].min
59
+ step.set_power_level new_pct
60
+ end
61
+ when 'c'.ord
62
+ if step.mode == :manual
63
+ new_pct = [(step.power_level - 0.05).round(2), 0.0].max
64
+ step.set_power_level new_pct
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Brewby::CLI::Application do
4
+ before do
5
+ @output = {
6
+ pin: 1,
7
+ pulse_range: 5000
8
+ }
9
+ @view = Brewby::VirtualView.new
10
+ Brewby::CLI::Views::Application.any_instance.stub(:load_parent_view).and_return(@view)
11
+ @application = Brewby::CLI::Application.new adapter: :test, outputs: [@output], inputs: [{}]
12
+ end
13
+
14
+ context 'rendering' do
15
+ before do
16
+ @application.name = 'Awesome Ale'
17
+ @application.add_step :temp_control, mode: :auto, mode: :auto, target: 155.0, duration: 15, input: @application.inputs.last
18
+ @application.view.render
19
+ end
20
+
21
+ it 'renders the recipe name' do
22
+ line = @view.readline(1).strip
23
+ line.should == "BREWBY: Brewing 'Awesome Ale'"
24
+ end
25
+
26
+ it 'renders the step counter' do
27
+ line = @view.readline(2).strip
28
+ line.should == 'Step 1/1: Auto Temp Control'
29
+ end
30
+
31
+ it 'renders the brew timer' do
32
+ line = @view.readline(16).strip
33
+ line.should == 'Brew Timer: 00:00:00' + ''.ljust(30) + 'Step Timer: 00:00:00'
34
+ end
35
+ end
36
+
37
+ context 'input handling' do
38
+ it 'jumps to the next step when the n key is pressed' do
39
+ @view.stub(:getch).and_return('n'.ord)
40
+ @application.add_step :temp_control, mode: :auto, mode: :auto, target: 155.0, duration: 15, input: @application.inputs.last
41
+ @application.start_step @application.steps.first
42
+ @application.view.handle_input
43
+ @application.current_step.should be_ended
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,6 @@
1
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
2
+
3
+ require 'brewby/cli'
4
+ require 'pry'
5
+
6
+ load './spec/support/virtual_view.rb'
@@ -0,0 +1,32 @@
1
+ recipe 'Honey Ale' do
2
+ step 'Strike Water' do
3
+ type :temp_control
4
+ mode :auto
5
+ target 168.0
6
+ hold_duration 5
7
+ input :hlt
8
+ output :hlt
9
+ end
10
+
11
+ step 'Infusion Mash Step' do
12
+ type :temp_control, mode: :auto, target: 150.0, duration: 60
13
+ input :mlt
14
+ output :hlt
15
+ end
16
+
17
+ step 'Fly Sparge' do
18
+ type :temp_control
19
+ mode :auto
20
+ target 168.0
21
+ hold_duration 45
22
+ input :hlt
23
+ output :mlt
24
+ end
25
+
26
+ step 'Boil' do
27
+ type :temp_control
28
+ mode :manual
29
+ input :bk
30
+ output :bk
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ require 'stringio'
2
+
3
+ module Brewby
4
+ class VirtualView
5
+ def initialize
6
+ @output = []
7
+ end
8
+
9
+ def move row, col
10
+ @output[row] ||= StringIO.new("".ljust(70))
11
+ @output[row].pos = col
12
+ @current_row = row
13
+ end
14
+
15
+ def addstr string
16
+ @output[@current_row].write string
17
+ end
18
+
19
+ def readline lineno
20
+ @output[lineno].string
21
+ end
22
+
23
+ def refresh
24
+ # no-op
25
+ end
26
+
27
+ def getch
28
+ # no-op. this will get stubbed by a test
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ describe Brewby::CLI::Views::TempControl do
4
+ let(:sensor) { Brewby::TempSensor.new 1 }
5
+ let(:adapter) { Brewby::Outputs::Test.new }
6
+ let(:element) { Brewby::HeatingElement.new adapter, pulse_width: 5000 }
7
+ let(:step) { Brewby::Steps::TempControl.new mode: :manual, input: sensor, output: element }
8
+ let(:view) { Brewby::VirtualView.new }
9
+ let(:step_view) { Brewby::CLI::Views::TempControl.new step, view }
10
+
11
+ describe 'rendering' do
12
+ let(:step) { Brewby::Steps::TempControl.new mode: :auto, target: 152.0, input: sensor, output: element }
13
+
14
+ before do
15
+ step.instance_variable_set(:@last_reading, 100.0)
16
+ step_view.render
17
+ end
18
+
19
+ it 'renders the default name of the step' do
20
+ line = view.readline(2).strip
21
+ line.should == "Auto Temp Control"
22
+ end
23
+
24
+ it 'renders the actual temperature' do
25
+ line = view.readline(5).strip
26
+ line.should == "Actual Temp: 100.0 F"
27
+ end
28
+
29
+ it 'renders the target temperature' do
30
+ line = view.readline(4).strip
31
+ line.should == "Target Temp: 152.0 F"
32
+ end
33
+
34
+ it 'renders the current power level' do
35
+ line = view.readline(6).strip
36
+ line.should == "Power Level: 0.0%"
37
+ end
38
+
39
+ it 'renders the step timer' do
40
+ line = view.readline(16).strip
41
+ line.should == "Step Timer: 00:00:00"
42
+ end
43
+ end
44
+
45
+ describe 'input handling' do
46
+ context 'in manual mode' do
47
+ it 'increases power level by 5% when e key is pressed' do
48
+ step.set_power_level 0.95
49
+ step_view.handle_input('e'.ord)
50
+ step.power_level.should == 1.0
51
+ end
52
+
53
+ it 'decreases power level by 5% when c key is pressed' do
54
+ step.set_power_level 0.85
55
+ step_view.handle_input('c'.ord)
56
+ step.power_level.should == 0.80
57
+ end
58
+ end
59
+
60
+ context 'in auto mode' do
61
+ let(:step) { Brewby::Steps::TempControl.new mode: :auto, target: 150.0,
62
+ input: sensor, output: element }
63
+
64
+ it 'does nothing when e key is pressed' do
65
+ step.set_power_level 0.80
66
+ step_view.handle_input('e'.ord)
67
+ step.power_level.should == 0.80
68
+ end
69
+
70
+ it 'does nothing when c key is pressed' do
71
+ step.set_power_level 0.80
72
+ step_view.handle_input('c'.ord)
73
+ step.power_level.should == 0.80
74
+ end
75
+ end
76
+ end
77
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: brewby-cli
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Nordman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ffi-ncurses
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: brewby
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 0.1.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 0.1.1
83
+ description:
84
+ email:
85
+ - cadwallion@gmail.com
86
+ executables:
87
+ - brewby
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .bundle/config
92
+ - .gitignore
93
+ - Gemfile
94
+ - Gemfile.lock
95
+ - LICENSE
96
+ - README.md
97
+ - Rakefile
98
+ - bin/autospec
99
+ - bin/brewby
100
+ - bin/htmldiff
101
+ - bin/ldiff
102
+ - bin/rspec
103
+ - brewby-cli.gemspec
104
+ - examples/brewby_recipe.rb
105
+ - examples/example_brewbyrc
106
+ - lib/brewby/cli.rb
107
+ - lib/brewby/cli/application.rb
108
+ - lib/brewby/cli/view.rb
109
+ - lib/brewby/cli/views/application.rb
110
+ - lib/brewby/cli/views/temp_control.rb
111
+ - spec/application_spec.rb
112
+ - spec/spec_helper.rb
113
+ - spec/support/sample_recipe.rb
114
+ - spec/support/virtual_view.rb
115
+ - spec/temp_control_spec.rb
116
+ homepage: ''
117
+ licenses: []
118
+ metadata: {}
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 2.0.14
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: An ncurses-based terminal application for the Brewby ecosystem
139
+ test_files:
140
+ - spec/application_spec.rb
141
+ - spec/spec_helper.rb
142
+ - spec/support/sample_recipe.rb
143
+ - spec/support/virtual_view.rb
144
+ - spec/temp_control_spec.rb