measurb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 041ff65242c85675992b2b42b67f1747c24f8e64
4
+ data.tar.gz: 37ec1b92574b3a80ee26999d295baf35824ebb7d
5
+ SHA512:
6
+ metadata.gz: c3539e48fb3b4bbe21e341d56907fa7bd4526ccebf61c5e4fe4379c3e9cd22c2c2b7f324c6c0677d74922d83978d112e6f533b0d50e8a811846c498d2b0bc2ca
7
+ data.tar.gz: e287a287a4f9bab984ff8f8addaeb8b4df0d75551985dd20c1e7c6230bbcac52a34800db7f3def1d039542c067a5c2ecccf13ffeee82c5f59e508dab95efb40a
data/.gitignore ADDED
@@ -0,0 +1,17 @@
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
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --warnings
3
+ --require spec_helper
4
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dims-rb.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Jeremy Fairbank
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,130 @@
1
+ # Measurb
2
+
3
+ Handle units of measurment with ease! Measurb is a Ruby library for creating and managing units of measurements, or dimensions. Create your own units and define how to convert amongst them. Measurb also comes with a few default dimensions: inches, feet, and yards, but you don't have to use them. Measurb takes care of the tediousness of adding, subtracting, and comparing different measurements, especially between different units of measurement.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'measurb'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install measurb
18
+
19
+ ## Defining Dimensions
20
+
21
+ Measurb has a straightforward interface to defining dimensions. Just give `Measurb.define` a dimension name and optional block to define conversions.
22
+
23
+ ```ruby
24
+ # Without conversions
25
+ Measurb.define :inches
26
+
27
+ # With conversion
28
+ Measurb.define :inches do
29
+ feet value / 12.0
30
+ yards value / 36.0
31
+ end
32
+
33
+ Measurb.define :feet do
34
+ inches value * 12.0
35
+ yards value / 3.0
36
+ end
37
+
38
+ Measurb.define :yards do
39
+ feet value * 3.0
40
+ inches value * 36.0
41
+ end
42
+ ```
43
+
44
+ You can specify an abbreviation for a dimension too.
45
+
46
+ ```ruby
47
+ Measurb.define :ft, abbrev: 'ft'
48
+ ```
49
+
50
+ ## Using Dimensions
51
+
52
+ When you define a dimension, Measurb creates a dimension class that can be instantiated.
53
+
54
+ ```ruby
55
+ Measurb.define :inches
56
+ forty_two_inches = Measurb::Inches.new(42)
57
+ ```
58
+
59
+ Merb also defines a singleton method on itself and a method on `Numeric`, both of the same dimension name.
60
+
61
+ ```ruby
62
+ two_inches = Measurb.inches(2) # singleton method
63
+ three_inches = 3.inches # Numeric method
64
+ ```
65
+
66
+ If you defined an abbreviation, you can use it on `Numeric` as well.
67
+
68
+ ```ruby
69
+ Measurb.define :ft, abbrev: 'ft'
70
+ 5.feet == 5.ft #=> true
71
+ ```
72
+
73
+ ## Converting
74
+
75
+ To convert a dimension, you must have set up at least two dimensions, including the appropriate conversion formulas.
76
+
77
+ ```ruby
78
+ Measurb.define :inches do
79
+ feet value / 12.0
80
+ end
81
+
82
+ Measurb.define :feet do
83
+ inches value * 12.0
84
+ end
85
+ ```
86
+
87
+ For every conversion you set up in the definition block, Measurb will add a `to_*` method for that conversion.
88
+
89
+ ```ruby
90
+ 24.inches.to_feet == 2.feet
91
+ 3.feet.to_inches == 36.inches
92
+ ```
93
+
94
+ ## Arithmetic
95
+
96
+ Measurb supports addition and subtraction currently. You can perform operations amongst all the defined dimension classes. Make sure you've define your conversions beforehand, though! The resulting value will use the class of the leftmost operand.
97
+
98
+ ```ruby
99
+ 2.feet + 12.inches == 3.feet
100
+ 3.feet - 6.inches == 2.5.feet
101
+ 3.yards - 1.feet == 2.yards
102
+ ```
103
+
104
+ ## Equality and Comparisons
105
+
106
+ Measurb also supports all the typical equality and inequality checks `==` `!=` `<` `>` `<=` `>=` `<=>`. They work correctly with other dimension classes too.
107
+
108
+ ```ruby
109
+ 42.feet == 42.feet #=> true
110
+ 2.feet < 26.inches #=> true
111
+ 3.feet > 2.yards #=> false
112
+ 24.inches <= 2.feet #=> true
113
+ 5.feet <=> 2.yards #=> -1
114
+ 24.inches != 2.feet #=> false
115
+ ```
116
+
117
+ `eql?` is also implemented, but it DOES depend on the same dimension class to be true
118
+
119
+ ```ruby
120
+ 2.feet.eql? 2.feet #=> true
121
+ 2.feet.eql? 24.inches #=> false
122
+ ```
123
+
124
+ ## Contributing
125
+
126
+ 1. Fork it ( http://github.com/jfairbank/measurb/fork )
127
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
128
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
129
+ 4. Push to the branch (`git push origin my-new-feature`)
130
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,32 @@
1
+ module Measurb
2
+ # Class for managing configuration of {Measurb}
3
+ class Config
4
+ # Enable defaults dimensions based on their name
5
+ #
6
+ # @api public
7
+ #
8
+ # @example
9
+ # Measurb.configure do |config|
10
+ # config.enable_defaults :inches, :feet
11
+ # end
12
+ #
13
+ # @param names [Symbol, String] The dimension names to enable
14
+ # @return [Array<Symbol, String>] The dimension names that were enabled
15
+ def enable_defaults(*names)
16
+ enabled = []
17
+
18
+ names.each do |name|
19
+ path = "measurb/defaults/#{name}"
20
+
21
+ begin
22
+ require path
23
+ enabled << name
24
+ rescue LoadError
25
+ warn "'#{name}' is not a default dimension"
26
+ end
27
+ end
28
+
29
+ enabled
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,33 @@
1
+ module Measurb
2
+ # Module for extending core classes
3
+ module CoreExt
4
+ # Add the dimension name method to `Numeric`
5
+ #
6
+ # @api semipublic
7
+ #
8
+ # @example
9
+ # 42.respond_to?(:inches) #=> false
10
+ #
11
+ # Measurb::CoreExt.add_numeric_dimension(:inches, 'Inches', 'in')
12
+ #
13
+ # 42.respond_to?(:inches) #=> true
14
+ #
15
+ # @param name [Symbol, String] Name of the dimension
16
+ # @param dimension_class_name [String] Name of the dimension class
17
+ # @param abbrev [String] Abbreviation for the dimension name
18
+ # @return [nil]
19
+ def self.add_numeric_dimension(name, dimension_class_name, abbrev)
20
+ def_string = <<-EOS
21
+ def #{name}(precision = #{DEFAULT_PRECISION})
22
+ Measurb::#{dimension_class_name}.new(self, precision)
23
+ end
24
+ EOS
25
+
26
+ unless abbrev.nil?
27
+ def_string << "\nalias_method :#{abbrev}, :#{name}"
28
+ end
29
+
30
+ Numeric.class_eval(def_string)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,4 @@
1
+ Measurb.define :feet, abbrev: 'ft' do
2
+ inches value * 12.0
3
+ yards value / 3.0
4
+ end
@@ -0,0 +1,4 @@
1
+ Measurb.define :inches, abbrev: 'in' do
2
+ feet value / 12.0
3
+ yards value / 36.0
4
+ end
@@ -0,0 +1,4 @@
1
+ Measurb.define :yards, abbrev: 'yd' do
2
+ feet value * 3.0
3
+ inches value * 36.0
4
+ end
@@ -0,0 +1,93 @@
1
+ module Measurb
2
+ # Base class for defined dimensions to inherit from.
3
+ class Dimension
4
+ include Comparable
5
+
6
+ attr_reader :value, :precision
7
+
8
+ class << self
9
+ attr_reader :abbrev, :dimension_name
10
+ end
11
+
12
+ # Initialize the dimension
13
+ #
14
+ # @param value [Numeric] Numeric value to wrap
15
+ # @param precision [Integer] Precision of decimal places
16
+ # @return [Measurb::Dimension]
17
+ def initialize(value, precision = DEFAULT_PRECISION)
18
+ @precision = precision
19
+ @original_value = value
20
+ @value = fix_value(value, precision)
21
+ end
22
+
23
+ # Add another dimension
24
+ #
25
+ # @param other [Measurb::Dimension]
26
+ # @return [Measurb::Dimension]
27
+ def +(other)
28
+ arithmetic(:+, other)
29
+ end
30
+
31
+ # Subtract another dimension
32
+ #
33
+ # @param other [Measurb::Dimension]
34
+ # @return [Measurb::Dimension]
35
+ def -(other)
36
+ arithmetic(:-, other)
37
+ end
38
+
39
+ # Compare with another dimension
40
+ #
41
+ # @param other [Measurb::Dimension]
42
+ # @return [-1, 0, 1]
43
+ def <=>(other)
44
+ value <=> to_self(other).value
45
+ end
46
+
47
+ # Check type and value quality with another dimension
48
+ #
49
+ # @param other [Measurb::Dimension]
50
+ # @return [Boolean]
51
+ def eql?(other)
52
+ self.class == other.class && self == other
53
+ end
54
+
55
+ # Get the inspect string
56
+ #
57
+ # @return [String]
58
+ def inspect
59
+ "#{value} #{self.class.abbrev || self.class.dimension_name}"
60
+ end
61
+
62
+ private
63
+
64
+ # Perform an arithmetic operation `name` with `other`, keeping the
65
+ # smallest precision of the two dimensions.
66
+ #
67
+ # @param op [Symbol] Name of the arithmetic operation
68
+ # @param other [Measurb::Dimension]
69
+ # @return [Measurb::Dimension]
70
+ def arithmetic(op, other)
71
+ least_precision = [precision, other.precision].min
72
+ new_value = value.__send__(op, to_self(other).value)
73
+ self.class.new(new_value, least_precision)
74
+ end
75
+
76
+ # Coerce other dimension to own class
77
+ #
78
+ # @param other [Measurb::Dimension]
79
+ # @return [self.class]
80
+ def to_self(other)
81
+ other.__send__("to_#{self.class.dimension_name}")
82
+ end
83
+
84
+ # Adjust a value to a given decimal precision
85
+ #
86
+ # @param value [Numeric]
87
+ # @param precision [Integer] Precision of decimal places
88
+ def fix_value(value, precision)
89
+ modifier = (10 ** precision).to_f
90
+ (value * modifier).round / modifier
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,108 @@
1
+ module Measurb
2
+ # Factory class for building new dimension classes
3
+ class DimensionBuilder
4
+ attr_reader :dimension_class_name, :value
5
+
6
+ # Get an appropriate class name for a dimension name
7
+ #
8
+ # @param name [Symbol, String] Name of the dimension
9
+ # @return [String] Name of the dimension class
10
+ def self.get_dimension_class_name(name)
11
+ name.to_s.split('_').map(&:capitalize).join
12
+ end
13
+
14
+ # Initialize the builder
15
+ #
16
+ # @param name [Symbol, String] Name of the dimension
17
+ # @param options [Hash]
18
+ # @option options [String] :abbrev (nil) The dimension abbreviation
19
+ # @param block [Proc] Block for defining conversions to other dimensions
20
+ def initialize(name, options = {}, &block)
21
+ @name = name
22
+ @def_block = block
23
+ @options = options
24
+ @dimension_class_name = self.class.get_dimension_class_name(name)
25
+ end
26
+
27
+ # @!attribute [r] dimension_class
28
+ # Get the dimension class, creating it if it's not available
29
+ # @return [Measurb::Dimension]
30
+ def dimension_class
31
+ build_dimension_class unless defined?(@dimension_class)
32
+ @dimension_class
33
+ end
34
+
35
+ # Use to build conversion methods to other dimensions
36
+ def method_missing(name, *args, &block)
37
+ build_default_conversion(name, args.first)
38
+ end
39
+
40
+ private
41
+
42
+ # Build a conversion to another dimension with a default implementation
43
+ #
44
+ # @param name [Symbol, String] Name of the dimension
45
+ # @param conversion [Proc] Proc to convert the actual value
46
+ def build_default_conversion(name, conversion)
47
+ class_name = self.class.get_dimension_class_name(name)
48
+
49
+ build_conversion(name) do
50
+ precision ||= self.precision
51
+ Measurb.const_get(class_name).new(instance_eval(&conversion), precision)
52
+ end
53
+ end
54
+
55
+ # Build a conversion method, using `block` as the body
56
+ #
57
+ # @param name [Symbol, String] Name of the dimension
58
+ # @param block [Proc] Conversion method body
59
+ def build_conversion(name, &block)
60
+ @dimension_class.__send__(:define_method, "to_#{name}", &block)
61
+ end
62
+
63
+ # Build the dimension class, defining any conversions from `@def_block` and
64
+ # defining a default conversion to itself
65
+ def build_dimension_class
66
+ @value = ValueProxy.new
67
+ @dimension_class = Class.new(Dimension)
68
+
69
+ @dimension_class.instance_variable_set(:@dimension_name, @name.to_s)
70
+ @dimension_class.instance_variable_set(:@abbrev, @options[:abbrev])
71
+
72
+ instance_eval(&@def_block) unless @def_block.nil?
73
+
74
+ # Return self when converting to same dimension
75
+ build_conversion(@name) { self }
76
+ end
77
+
78
+ # Placeholder class in definition blocks for writing straightforward conversion syntax.
79
+ # Currently only supports multiplication and division.
80
+ #
81
+ # ==== Examples
82
+ #
83
+ # Measurb.define :inches do
84
+ # feet value / 12.0
85
+ # end
86
+ #
87
+ # Measurb.define :feet do
88
+ # inches value * 12.0
89
+ # end
90
+ class ValueProxy
91
+ # Handle a conversion by multiplication
92
+ #
93
+ # @param convert_value [Float]
94
+ # @return [Proc] Proc to be used as the body for the conversion method on the {Dimension dimension class}
95
+ def *(convert_value)
96
+ proc { value * convert_value }
97
+ end
98
+
99
+ # Handle a conversion by division
100
+ #
101
+ # @param convert_value [Float]
102
+ # @return [Proc] Proc to be used as the body for the conversion method on the {Dimension dimension class}
103
+ def /(convert_value)
104
+ proc { value / convert_value }
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,3 @@
1
+ module Measurb
2
+ VERSION = '0.0.1'
3
+ end
data/lib/measurb.rb ADDED
@@ -0,0 +1,109 @@
1
+ require 'measurb/version'
2
+ require 'measurb/config'
3
+ require 'measurb/core_ext'
4
+ require 'measurb/dimension'
5
+ require 'measurb/dimension_builder'
6
+
7
+ # Main module
8
+ module Measurb
9
+ DEFAULT_PRECISION = 3
10
+
11
+ # Error when attempting to define a dimension that already exists
12
+ class DuplicateDimensionError < NameError; end
13
+
14
+ class << self
15
+ # Define a new dimension class and helper singleton method
16
+ #
17
+ # @api public
18
+ #
19
+ # @example Without conversions
20
+ # Measurb.define :inches
21
+ #
22
+ # @example With conversions
23
+ # Measurb.define :inches do
24
+ # feet value / 12.0
25
+ # end
26
+ #
27
+ # Measurb.define :feet do
28
+ # inches value * 12.0
29
+ # end
30
+ #
31
+ # @param name [Symbol, String] Name of the dimension
32
+ # @return [Measurb::Dimension] A subclass of {Measurb::Dimension}
33
+ def define(name, options = {}, &block)
34
+ # Check if the dimension has already been defined
35
+ if dimension_exists?(name)
36
+ raise DuplicateDimensionError,
37
+ "Already defined dimension class `#{DimensionBuilder.get_dimension_class_name(name)}`"
38
+ end
39
+
40
+ # Create the dimension builder
41
+ builder = DimensionBuilder.new(name, options, &block)
42
+
43
+ # Add the class constant and helper method to the module
44
+ const_set(builder.dimension_class_name, builder.dimension_class)
45
+ add_dimension_method(name, builder.dimension_class_name)
46
+
47
+ # Add the helper methods to 'Numeric'
48
+ CoreExt.add_numeric_dimension(name, builder.dimension_class_name, builder.dimension_class.abbrev)
49
+
50
+ builder.dimension_class
51
+ end
52
+
53
+ # Configure {Measurb} with {Config}
54
+ #
55
+ # @api public
56
+ #
57
+ # @example
58
+ # Measurb.configure do |config|
59
+ # config.enable_defaults :inches, :feet
60
+ # end
61
+ #
62
+ # @return [nil]
63
+ def configure
64
+ yield config
65
+ end
66
+
67
+ # Check if the dimension already exists
68
+ #
69
+ # @api public
70
+ #
71
+ # @example
72
+ # Measurb.configure { |config| config.enable_defaults(:inches) }
73
+ #
74
+ # Measurb.dimension_exists?(:inches) #=> true
75
+ # Measurb.dimension_exists?(:feet) #=> false
76
+ #
77
+ # @param name [Symbol, String] Name of the dimension
78
+ # @return [Boolean]
79
+ def dimension_exists?(name)
80
+ const_defined?(DimensionBuilder.get_dimension_class_name(name))
81
+ end
82
+
83
+ private
84
+
85
+ # Config object used by {#configure}
86
+ #
87
+ # @api private
88
+ #
89
+ # @return [Config] The configurable object
90
+ def config
91
+ @config ||= Config.new
92
+ end
93
+
94
+ # Create the dimension class singleton method
95
+ #
96
+ # @api private
97
+ #
98
+ # @param name [Symbol, String] Name of the dimension
99
+ # @param dimension_class_name [String] Name of the dimension class
100
+ # @return [Symbol, nil] Return type based on ruby version
101
+ def add_dimension_method(name, dimension_class_name)
102
+ instance_eval <<-EOS, __FILE__, __LINE__ + 1
103
+ def #{name}(value, precision = DEFAULT_PRECISION)
104
+ #{dimension_class_name}.new(value, precision)
105
+ end
106
+ EOS
107
+ end
108
+ end
109
+ end
data/measurb.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'measurb/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'measurb'
8
+ spec.version = Measurb::VERSION
9
+ spec.authors = ['Jeremy Fairbank']
10
+ spec.email = ['elpapapollo@gmail.com']
11
+ spec.summary = %q{Handle units of measurement}
12
+ spec.description = %q{Handle units of measurement}
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
+
16
+ #spec.files = `git ls-files -z`.split('\x0')
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.5'
23
+ spec.add_development_dependency 'rake'
24
+ spec.add_development_dependency 'rspec', '~> 3.0.0'
25
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe Measurb::Dimension do
4
+ before :context do
5
+ clear_defined_inches
6
+ clear_defined_feet
7
+ clear_defined_yards
8
+ remove_loaded_default_dimensions
9
+
10
+ Measurb.configure do |config|
11
+ config.enable_defaults :inches, :feet
12
+ end
13
+ end
14
+
15
+ let(:inches) { 24.inches }
16
+ let(:feet) { 5.feet }
17
+
18
+ context 'when adding' do
19
+ it 'returns the left hand side class' do
20
+ expect(inches + inches).to be_a(Measurb::Inches)
21
+ expect(inches + feet).to be_a(Measurb::Inches)
22
+ expect(feet + feet).to be_a(Measurb::Feet)
23
+ expect(feet + inches).to be_a(Measurb::Feet)
24
+ end
25
+
26
+ it 'adds correctly' do
27
+ expect(inches + inches).to have_value(48)
28
+ expect(inches + feet).to have_value(84)
29
+ expect(feet + feet).to have_value(10)
30
+ expect(feet + inches).to have_value(7)
31
+ end
32
+
33
+ it 'respects the smallest precision' do
34
+ x = Math::PI.inches(4)
35
+ y = 2.001.inches(3)
36
+ sum = x + y
37
+
38
+ expect(sum).to have_precision(3)
39
+ expect(sum).to have_value(5.143)
40
+ end
41
+ end
42
+
43
+ context 'when subtracting' do
44
+ it 'returns the left hand side class' do
45
+ expect(inches - inches).to be_a(Measurb::Inches)
46
+ expect(inches - feet).to be_a(Measurb::Inches)
47
+ expect(feet - feet).to be_a(Measurb::Feet)
48
+ expect(feet - inches).to be_a(Measurb::Feet)
49
+ end
50
+
51
+ it 'subtracts correctly' do
52
+ expect(inches - inches).to have_value(0)
53
+ expect(inches - feet).to have_value(-36)
54
+ expect(feet - feet).to have_value(0)
55
+ expect(feet - inches).to have_value(3)
56
+ end
57
+
58
+ it 'respects the smallest precision' do
59
+ x = Math::PI.inches(4)
60
+ y = 2.001.inches(3)
61
+ difference = x - y
62
+
63
+ expect(difference).to have_precision(3)
64
+ expect(difference).to have_value(1.141)
65
+ end
66
+ end
67
+ end