brewby-cli 0.1.0

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