gas-blender 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +7 -0
- data/gas-blender.gemspec +24 -0
- data/lib/gas-blender.rb +67 -0
- data/lib/gas-blender/fill.rb +83 -0
- data/lib/gas-blender/length.rb +17 -0
- data/lib/gas-blender/measure.rb +54 -0
- data/lib/gas-blender/mix.rb +9 -0
- data/lib/gas-blender/pressure.rb +70 -0
- data/lib/gas-blender/tank.rb +14 -0
- data/lib/gas-blender/version.rb +3 -0
- data/spec/gas-blender/fill_spec.rb +155 -0
- data/spec/gas-blender/mix_spec.rb +25 -0
- data/spec/gas-blender/pressure_spec.rb +108 -0
- metadata +107 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c2d08271e4a3efb7c9e14dfca0eb6e5b8ebca38c
|
4
|
+
data.tar.gz: 7dc1a5fb5875854107e64ded6e1355354b1627d6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 599ca17e9b87996f84ea6e751ef96cbc0141b7aaf95a20d0a65767aeb6c98c6c2fd5fa6e1abf0edbc0fc763f77e5175847bc11e0dbe1a56ea182e41743e468c2
|
7
|
+
data.tar.gz: 30dfbfaa0fc66a1c481063eda6429f306cbf51ab6200d78adb5b49c7fcef5cfcf779098af171757725902ba5244c0c968babb2a2f87556cb09a335df52eecc29
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
.rspec
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0-p481
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Ken Mayer
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Gas::Blender
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'gas-blender'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install gas-blender
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it ( https://github.com/[my-github-username]/gas-blender/fork )
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/gas-blender.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'gas-blender/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "gas-blender"
|
8
|
+
spec.version = GasBlender::VERSION
|
9
|
+
spec.authors = ["Ken Mayer"]
|
10
|
+
spec.email = ["ken@bitwrangler.com"]
|
11
|
+
spec.summary = %q{Gas blending tools for SCUBA divers}
|
12
|
+
spec.description = %q{Gas blending tools for SCUBA divers. A thought experiment.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
end
|
data/lib/gas-blender.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative "gas-blender/version"
|
2
|
+
require_relative "gas-blender/pressure"
|
3
|
+
require_relative "gas-blender/length"
|
4
|
+
require_relative "gas-blender/tank"
|
5
|
+
require_relative "gas-blender/fill"
|
6
|
+
require_relative "gas-blender/mix"
|
7
|
+
|
8
|
+
module GasBlender
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def Pressure(arg)
|
12
|
+
case arg
|
13
|
+
when Bar, PSI
|
14
|
+
arg
|
15
|
+
when String
|
16
|
+
string_conversion(arg)
|
17
|
+
else
|
18
|
+
raise TypeError, "Can not convert #{arg.inspect} to Pressure"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def self.string_conversion(arg)
|
25
|
+
case
|
26
|
+
when arg =~ /(\d.*) bar/
|
27
|
+
Bar.new($1.to_f)
|
28
|
+
when arg =~ /(\d.*) psi/
|
29
|
+
PSI.new($1.to_f)
|
30
|
+
else
|
31
|
+
raise TypeError, "Can not convert #{arg.inspect} to Pressure"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Fixnum
|
37
|
+
def bar
|
38
|
+
GasBlender::Bar.new(self)
|
39
|
+
end
|
40
|
+
def psi
|
41
|
+
GasBlender::PSI.new(self)
|
42
|
+
end
|
43
|
+
def ean
|
44
|
+
GasBlender::Mix.new(self / 100.0)
|
45
|
+
end
|
46
|
+
def feet
|
47
|
+
GasBlender::Feet.new(self)
|
48
|
+
end
|
49
|
+
def meters
|
50
|
+
GasBlender::Meter.new(self)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Float
|
55
|
+
def bar
|
56
|
+
GasBlender::Bar.new(self)
|
57
|
+
end
|
58
|
+
def psi
|
59
|
+
GasBlender::PSI.new(self)
|
60
|
+
end
|
61
|
+
def feet
|
62
|
+
GasBlender::Feet.new(self)
|
63
|
+
end
|
64
|
+
def meters
|
65
|
+
GasBlender::Meter.new(self)
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module GasBlender
|
2
|
+
class Fill
|
3
|
+
attr_reader :mix
|
4
|
+
attr_reader :tank
|
5
|
+
attr_reader :fill_mix
|
6
|
+
attr_reader :top_off_mix
|
7
|
+
|
8
|
+
def initialize(attributes)
|
9
|
+
@mix = attributes.delete(:mix) || Mix.new(0.21)
|
10
|
+
@tank = attributes.delete(:tank)
|
11
|
+
@fill_mix = attributes.delete(:fill_mix) || Mix.new(1.0)
|
12
|
+
@top_off_mix = attributes.delete(:top_off_mix) || Mix.new(0.21)
|
13
|
+
raise RuntimeError, "Invalid attributes: #{attributes.keys.inspect}" unless attributes == {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def pressure
|
17
|
+
if !pressure_need.zero?
|
18
|
+
(pressure_need * ((fO2_need - top_off_mix) / (fill_mix - top_off_mix))) + pressure_have
|
19
|
+
else
|
20
|
+
(pressure_want * (fO2_want - top_off_mix)) / (fO2_have - top_off_mix)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def mod(max_ppO2)
|
25
|
+
case tank.service_pressure
|
26
|
+
when GasBlender::PSI
|
27
|
+
mod_fsw(max_ppO2)
|
28
|
+
when GasBlender::Bar
|
29
|
+
mod_msw(max_ppO2)
|
30
|
+
else
|
31
|
+
raise TypeError, "Unknown tank service pressure, #{tank.inspect}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def mod_fsw(max_ppO2)
|
36
|
+
mod_atm(max_ppO2).to_fsw - GasBlender::ATM.new(1.0).to_fsw
|
37
|
+
end
|
38
|
+
|
39
|
+
def mod_msw(max_ppO2)
|
40
|
+
mod_atm(max_ppO2).to_msw - GasBlender::ATM.new(1.0).to_msw
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
alias :fO2_want :mix
|
46
|
+
|
47
|
+
def fO2_have
|
48
|
+
Mix.new(tank.current_mix)
|
49
|
+
end
|
50
|
+
|
51
|
+
def fO2_need
|
52
|
+
Mix.new(ppO2_need / pressure_need)
|
53
|
+
end
|
54
|
+
|
55
|
+
def ppO2_want
|
56
|
+
tank.service_pressure * fO2_want
|
57
|
+
end
|
58
|
+
|
59
|
+
def ppO2_have
|
60
|
+
tank.current_pressure * fO2_have
|
61
|
+
end
|
62
|
+
|
63
|
+
def ppO2_need
|
64
|
+
ppO2_want - ppO2_have
|
65
|
+
end
|
66
|
+
|
67
|
+
def pressure_want
|
68
|
+
tank.service_pressure
|
69
|
+
end
|
70
|
+
|
71
|
+
def pressure_have
|
72
|
+
tank.current_pressure
|
73
|
+
end
|
74
|
+
|
75
|
+
def pressure_need
|
76
|
+
pressure_want - pressure_have
|
77
|
+
end
|
78
|
+
|
79
|
+
def mod_atm(max_ppO2)
|
80
|
+
GasBlender::ATM.new((max_ppO2.to_bar / mix) / Bar.new(1.0))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative "measure"
|
2
|
+
|
3
|
+
module GasBlender
|
4
|
+
class Length < Measure
|
5
|
+
end
|
6
|
+
|
7
|
+
class Feet < Length
|
8
|
+
def to_s
|
9
|
+
"%.#{PRECISION}f feet" % magnitude
|
10
|
+
end
|
11
|
+
end
|
12
|
+
class Meter < Length
|
13
|
+
def to_s
|
14
|
+
"%.#{PRECISION}f m" % magnitude
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module GasBlender
|
2
|
+
class Measure
|
3
|
+
include Comparable
|
4
|
+
|
5
|
+
PRECISION = 8
|
6
|
+
|
7
|
+
def initialize(magnitude)
|
8
|
+
@magnitude = magnitude.to_f
|
9
|
+
freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
def inspect
|
13
|
+
"%.#{PRECISION}f" % magnitude
|
14
|
+
end
|
15
|
+
|
16
|
+
def <=>(other)
|
17
|
+
other.is_a?(self.class) && magnitude <=> other.magnitude
|
18
|
+
end
|
19
|
+
alias_method :eql?, :==
|
20
|
+
|
21
|
+
def hash
|
22
|
+
[magnitude, self.class].hash
|
23
|
+
end
|
24
|
+
|
25
|
+
def -(other)
|
26
|
+
raise TypeError, "#{other.inspect} is not a #{self.class}" unless other.is_a?(self.class)
|
27
|
+
self.class.new(magnitude - other.magnitude)
|
28
|
+
end
|
29
|
+
|
30
|
+
def *(factor)
|
31
|
+
self.class.new(magnitude * factor.to_f)
|
32
|
+
end
|
33
|
+
|
34
|
+
def /(denominator)
|
35
|
+
if denominator.class == self.class
|
36
|
+
magnitude / denominator.magnitude.to_f
|
37
|
+
else
|
38
|
+
self.class.new(magnitude / denominator.to_f)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def abs
|
43
|
+
self.class.new(magnitude.abs)
|
44
|
+
end
|
45
|
+
|
46
|
+
def zero?
|
47
|
+
magnitude.round(PRECISION) == 0.0
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
attr_reader :magnitude
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require_relative "measure"
|
2
|
+
|
3
|
+
module GasBlender
|
4
|
+
class Pressure < Measure
|
5
|
+
def <=>(other)
|
6
|
+
other = GasBlender::Pressure(other)
|
7
|
+
magnitude.round(PRECISION) <=> other.send(converter).magnitude.round(PRECISION)
|
8
|
+
end
|
9
|
+
|
10
|
+
def -(other)
|
11
|
+
other = GasBlender::Pressure(other)
|
12
|
+
self.class.new(magnitude - other.send(converter).magnitude)
|
13
|
+
end
|
14
|
+
|
15
|
+
def +(other)
|
16
|
+
other = GasBlender::Pressure(other)
|
17
|
+
self.class.new(magnitude + other.send(converter).magnitude)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Bar < Pressure
|
22
|
+
def to_s
|
23
|
+
"%.#{PRECISION}f bar" % magnitude
|
24
|
+
end
|
25
|
+
|
26
|
+
def converter
|
27
|
+
:to_bar
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_bar
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_psi
|
35
|
+
PSI.new(magnitude * 14.5037738)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class PSI < Pressure
|
40
|
+
def to_s
|
41
|
+
"%.#{PRECISION}f psi" % magnitude
|
42
|
+
end
|
43
|
+
|
44
|
+
def converter
|
45
|
+
:to_psi
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_psi
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_bar
|
53
|
+
Bar.new(magnitude * 0.0689475729)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class ATM < Pressure
|
58
|
+
def to_s
|
59
|
+
"%.#{PRECISION}f atm" % magnitude
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_fsw
|
63
|
+
Feet.new(33) * self.magnitude
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_msw
|
67
|
+
Meter.new(10) * self.magnitude
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module GasBlender
|
2
|
+
class Tank
|
3
|
+
attr_reader :service_pressure
|
4
|
+
attr_reader :current_pressure
|
5
|
+
attr_reader :current_mix
|
6
|
+
|
7
|
+
def initialize(attributes = {})
|
8
|
+
@service_pressure = GasBlender::Pressure(attributes.delete(:service_pressure))
|
9
|
+
@current_pressure = GasBlender::Pressure(attributes.delete(:current_pressure) || service_pressure.class.new(0))
|
10
|
+
@current_mix = attributes.delete(:current_mix) || 0.21
|
11
|
+
raise RuntimeError, "Invalid attributes: #{attributes.keys.inspect}" unless attributes == {}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require "gas-blender"
|
2
|
+
|
3
|
+
module GasBlender
|
4
|
+
describe Fill do
|
5
|
+
describe "top off pressure" do
|
6
|
+
it "given an empty tank, fill to 200 bar with EAN32" do
|
7
|
+
tank = Tank.new(
|
8
|
+
service_pressure: 200.bar
|
9
|
+
)
|
10
|
+
fill = Fill.new(
|
11
|
+
mix: 32.ean,
|
12
|
+
tank: tank
|
13
|
+
)
|
14
|
+
expect(fill.pressure).to be_within(0.05.bar).of(27.8.bar)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "given an empty tank, fill to 3000 psi with EAN36" do
|
18
|
+
tank = Tank.new(
|
19
|
+
service_pressure: 3000.psi
|
20
|
+
)
|
21
|
+
fill = Fill.new(
|
22
|
+
mix: 36.ean,
|
23
|
+
tank: tank
|
24
|
+
)
|
25
|
+
expect(fill.pressure).to be_within(0.05.psi).of(569.6.psi)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "given a tank with 1467 psi of EAN29, fill to 200 bar of EAN 36" do
|
29
|
+
tank = Tank.new(
|
30
|
+
service_pressure: 200.bar,
|
31
|
+
current_pressure: 67.bar,
|
32
|
+
current_mix: 32.ean
|
33
|
+
)
|
34
|
+
fill = Fill.new(
|
35
|
+
mix: 36.ean,
|
36
|
+
tank: tank
|
37
|
+
)
|
38
|
+
expect(fill.pressure).to be_within(0.05.bar).of(tank.current_pressure + 28.6.bar)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "given a tank with 1000 psi of EAN28, fill to 3000 psi of EAN36 with EAN50" do
|
42
|
+
tank = Tank.new(
|
43
|
+
service_pressure: 3000.psi,
|
44
|
+
current_pressure: 1000.psi,
|
45
|
+
current_mix: 28.ean
|
46
|
+
)
|
47
|
+
fill = Fill.new(
|
48
|
+
mix: 36.ean,
|
49
|
+
tank: tank,
|
50
|
+
fill_mix: 50.ean
|
51
|
+
)
|
52
|
+
expect(fill.pressure).to be_within(0.5.psi).of(tank.current_pressure + 1310.psi)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "given an empty tank, fill to 232 bar of EAN36 with EAN100, top off with EAN32" do
|
56
|
+
tank = Tank.new(
|
57
|
+
service_pressure: 232.bar
|
58
|
+
)
|
59
|
+
fill = Fill.new(
|
60
|
+
mix: 36.ean,
|
61
|
+
tank: tank,
|
62
|
+
top_off_mix: 32.ean
|
63
|
+
)
|
64
|
+
expect(fill.pressure).to be_within(0.05.bar).of(tank.current_pressure + 13.6.bar)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "given a tank with 220 bar of EAN36, bleed to 161.3 and fill with air" do
|
68
|
+
tank = Tank.new(
|
69
|
+
service_pressure: 220.bar,
|
70
|
+
current_pressure: 220.bar,
|
71
|
+
current_mix: 36.ean
|
72
|
+
)
|
73
|
+
fill = Fill.new(
|
74
|
+
mix: 32.ean,
|
75
|
+
tank: tank
|
76
|
+
)
|
77
|
+
expect(fill.pressure).to be_within(0.05.bar).of(tank.current_pressure - 58.7.bar)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Some more examples from the workbook
|
81
|
+
it "given a tank with 720 psi of 31.3, fill to 3000 psi of EAN31" do
|
82
|
+
tank = Tank.new(
|
83
|
+
service_pressure: 3000.psi,
|
84
|
+
current_pressure: 720.psi,
|
85
|
+
current_mix: Mix.new(0.313)
|
86
|
+
)
|
87
|
+
fill = Fill.new(
|
88
|
+
mix: 31.ean,
|
89
|
+
tank: tank
|
90
|
+
)
|
91
|
+
expect(fill.pressure).to be_within(1.psi).of(1005.psi)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "given an empty tank, fill to 3000 psi with EAN31" do
|
95
|
+
tank = Tank.new(service_pressure: 3000.psi)
|
96
|
+
fill = Fill.new(mix: 31.ean, tank: tank)
|
97
|
+
expect(fill.pressure).to be_within(1.psi).of(380.psi)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "given a tank with 190 psi of 31.7%, fill to 3000 psi of EAN31" do
|
101
|
+
tank = Tank.new(
|
102
|
+
service_pressure: 3000.psi,
|
103
|
+
current_pressure: 190.psi,
|
104
|
+
current_mix: Mix.new(0.317)
|
105
|
+
)
|
106
|
+
fill = Fill.new(
|
107
|
+
mix: 31.ean,
|
108
|
+
tank: tank
|
109
|
+
)
|
110
|
+
expect(fill.pressure).to be_within(1.psi).of(544.psi)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "maximum operating depth" do
|
115
|
+
# http://en.wikipedia.org/wiki/Maximum_operating_depth
|
116
|
+
context "Imperial" do
|
117
|
+
let(:tank) { Tank.new(service_pressure: 3000.psi)}
|
118
|
+
|
119
|
+
it "given EAN36 and max ppO2 of 1.4" do
|
120
|
+
fill = Fill.new(mix: 36.ean, tank: tank)
|
121
|
+
expect(fill.mod(1.4.bar)).to be_within(0.1.feet).of(95.3.feet)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "EAN3 and max ppO2 of 1.6" do
|
125
|
+
fill = Fill.new(mix: 3.ean)
|
126
|
+
expect(fill.mod_fsw(1.6.bar)).to be_within(1.feet).of(1727.feet)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "EAN100 and max ppO2 of 1.2" do
|
130
|
+
fill = Fill.new(mix: 100.ean)
|
131
|
+
expect(fill.mod_fsw(1.2.bar)).to be_within(1.feet).of(6.feet)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context "Metric" do
|
136
|
+
let(:tank) { Tank.new(service_pressure: 200.bar)}
|
137
|
+
|
138
|
+
it "given EAN36 and ppO2 of 1.4" do
|
139
|
+
fill = Fill.new(mix: 36.ean, tank: tank)
|
140
|
+
expect(fill.mod(1.4.bar)).to be_within(0.1.meters).of(28.9.meters)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "EAN3 and max ppO2 of 1.2" do
|
144
|
+
fill = Fill.new(mix: 3.ean)
|
145
|
+
expect(fill.mod_msw(1.2.bar)).to be_within(0.1.meters).of(390.0.meters)
|
146
|
+
end
|
147
|
+
|
148
|
+
it "EAN100 and max ppO2 of 1.6" do
|
149
|
+
fill = Fill.new(mix: 100.ean)
|
150
|
+
expect(fill.mod_msw(1.6.bar)).to be_within(0.1.meters).of(6.0.meters)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "gas-blender"
|
2
|
+
|
3
|
+
module GasBlender
|
4
|
+
describe Mix do
|
5
|
+
subject(:mix) { Mix.new(0.32) }
|
6
|
+
it "is immutable" do
|
7
|
+
expect(mix).to be_frozen
|
8
|
+
end
|
9
|
+
|
10
|
+
it "can convert to a float" do
|
11
|
+
expect(mix.to_f).to eq(0.32)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "implements Comparable" do
|
15
|
+
expect(Mix.new(0.36) <=> Mix.new(0.28)).to eq(1)
|
16
|
+
expect(Mix.new(0.28) <=> Mix.new(0.28)).to eq(0)
|
17
|
+
expect(Mix.new(0.28) <=> Mix.new(0.36)).to eq(-1)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "is hashable" do
|
21
|
+
expect(Mix.new(0.36).hash).to eq(Mix.new(0.36).hash)
|
22
|
+
expect(Mix.new(0.36)).to be_eql(Mix.new(0.36))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require "gas-blender"
|
2
|
+
|
3
|
+
module GasBlender
|
4
|
+
describe Pressure do
|
5
|
+
subject(:pressure) { Pressure.new(1) }
|
6
|
+
|
7
|
+
it "is immutable" do
|
8
|
+
expect(pressure).to be_frozen
|
9
|
+
end
|
10
|
+
|
11
|
+
it "is hashes by magnitude and class" do
|
12
|
+
expect(Pressure.new(1).hash).to eq(Pressure.new(1).hash)
|
13
|
+
expect(Pressure.new(1).hash).not_to eq(Bar.new(1).hash)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe Bar do
|
18
|
+
subject(:pressure) { Bar.new(1) }
|
19
|
+
|
20
|
+
it "has a nice string representation" do
|
21
|
+
expect(pressure.to_s).to eq("1.00000000 bar")
|
22
|
+
end
|
23
|
+
|
24
|
+
it "is equal by value" do
|
25
|
+
expect(pressure).to eq(Bar.new(1))
|
26
|
+
end
|
27
|
+
|
28
|
+
it "equal values have eql? hashes" do
|
29
|
+
expect(Bar.new(1)).to be_eql(Bar.new(1))
|
30
|
+
end
|
31
|
+
|
32
|
+
it "is not rude by comparison" do
|
33
|
+
expect(pressure).to_not eq("fish")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "will implicitly convert, however" do
|
37
|
+
expect(pressure).to eq(PSI.new(14.5037738))
|
38
|
+
end
|
39
|
+
|
40
|
+
it "implements Comparable" do
|
41
|
+
expect(Bar.new(9) <=> Bar.new(5)).to eq(1)
|
42
|
+
expect(Bar.new(5) <=> Bar.new(5)).to eq(0)
|
43
|
+
expect(Bar.new(5) <=> Bar.new(9)).to eq(-1)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "converts to bar" do
|
47
|
+
expect(pressure.to_bar).to eq(Bar.new(1))
|
48
|
+
end
|
49
|
+
|
50
|
+
it "converts to psi" do
|
51
|
+
expect(pressure.to_psi).to eq(PSI.new(14.5037738))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe PSI do
|
56
|
+
subject(:pressure) { PSI.new(1) }
|
57
|
+
|
58
|
+
it "has a nice string representation" do
|
59
|
+
expect(pressure.to_s).to eq("1.00000000 psi")
|
60
|
+
end
|
61
|
+
|
62
|
+
it "is equal by value" do
|
63
|
+
expect(pressure).to eq(PSI.new(1))
|
64
|
+
end
|
65
|
+
|
66
|
+
it "equal values have eql? hashes" do
|
67
|
+
expect(PSI.new(1)).to be_eql(PSI.new(1))
|
68
|
+
end
|
69
|
+
|
70
|
+
it "is not rude by comparison" do
|
71
|
+
expect(pressure).to_not eq("fish")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "will implicitly convert, however" do
|
75
|
+
expect(pressure).to eq(Bar.new(0.0689475729))
|
76
|
+
end
|
77
|
+
|
78
|
+
it "converts to bar" do
|
79
|
+
expect(pressure.to_bar).to eq(Bar.new(0.0689475729))
|
80
|
+
end
|
81
|
+
|
82
|
+
it "converts to psi" do
|
83
|
+
expect(pressure.to_psi).to eq(PSI.new(1))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "Conversion function" do
|
88
|
+
it "is idempotent" do
|
89
|
+
expect(GasBlender::Pressure(Bar.new(1))).to eq(Bar.new(1))
|
90
|
+
expect(GasBlender::Pressure(PSI.new(1))).to eq(PSI.new(1))
|
91
|
+
end
|
92
|
+
|
93
|
+
it "parses strings" do
|
94
|
+
expect(GasBlender::Pressure("1 bar")).to eq(Bar.new(1))
|
95
|
+
expect(GasBlender::Pressure("1 psi")).to eq(PSI.new(1))
|
96
|
+
end
|
97
|
+
|
98
|
+
it "raises a helpful error" do
|
99
|
+
expect {
|
100
|
+
GasBlender::Pressure(1.0)
|
101
|
+
}.to raise_error(TypeError)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "EAN" do
|
105
|
+
expect(32.ean).to eq(Mix.new(0.32))
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gas-blender
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ken Mayer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
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: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Gas blending tools for SCUBA divers. A thought experiment.
|
56
|
+
email:
|
57
|
+
- ken@bitwrangler.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- .ruby-version
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- gas-blender.gemspec
|
69
|
+
- lib/gas-blender.rb
|
70
|
+
- lib/gas-blender/fill.rb
|
71
|
+
- lib/gas-blender/length.rb
|
72
|
+
- lib/gas-blender/measure.rb
|
73
|
+
- lib/gas-blender/mix.rb
|
74
|
+
- lib/gas-blender/pressure.rb
|
75
|
+
- lib/gas-blender/tank.rb
|
76
|
+
- lib/gas-blender/version.rb
|
77
|
+
- spec/gas-blender/fill_spec.rb
|
78
|
+
- spec/gas-blender/mix_spec.rb
|
79
|
+
- spec/gas-blender/pressure_spec.rb
|
80
|
+
homepage: ''
|
81
|
+
licenses:
|
82
|
+
- MIT
|
83
|
+
metadata: {}
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 2.0.14
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: Gas blending tools for SCUBA divers
|
104
|
+
test_files:
|
105
|
+
- spec/gas-blender/fill_spec.rb
|
106
|
+
- spec/gas-blender/mix_spec.rb
|
107
|
+
- spec/gas-blender/pressure_spec.rb
|