ruby-measurement 0.0.1 → 1.0.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.
- data/lib/ruby-measurement/measurement.rb +51 -39
- data/lib/ruby-measurement/version.rb +1 -1
- data/ruby-measurement.gemspec +1 -1
- metadata +4 -4
@@ -2,17 +2,26 @@ require 'ruby-measurement/unit'
|
|
2
2
|
require 'ruby-measurement/version'
|
3
3
|
|
4
4
|
class Measurement
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
UNIT_REGEX = /([a-zA-Z].*)/.freeze
|
6
|
+
SCIENTIFIC_NUMBER = /([+-]?\d*\.?\d+(?:[Ee][+-]?)?\d*)/.freeze
|
7
|
+
SCIENTIFIC_REGEX = /\A#{SCIENTIFIC_NUMBER}\s*#{UNIT_REGEX}?\z/.freeze
|
8
|
+
RATIONAL_REGEX = /\A([+-]?\d+\s+)?((\d+)\/(\d+))?\s*#{UNIT_REGEX}?\z/.freeze
|
9
|
+
COMPLEX_REGEX = /\A#{SCIENTIFIC_NUMBER}?#{SCIENTIFIC_NUMBER}i\s*#{UNIT_REGEX}?\z/.freeze
|
8
10
|
|
9
11
|
attr_reader :quantity, :unit
|
10
12
|
|
11
13
|
class << self; attr_accessor :units end
|
12
14
|
@units = {}
|
13
15
|
|
14
|
-
def initialize(
|
15
|
-
|
16
|
+
def initialize(quantity, unit_name = :count)
|
17
|
+
unit = unit_name
|
18
|
+
unit = self.class.units[unit_name.to_s] if unit_name.kind_of?(Symbol) || unit_name.kind_of?(String)
|
19
|
+
|
20
|
+
raise ArgumentError, "Invalid quantity: #{quantity}" unless quantity.kind_of?(Numeric)
|
21
|
+
raise ArgumentError, "Invalid unit: #{unit_name}" unless unit.kind_of?(Unit)
|
22
|
+
|
23
|
+
@quantity = quantity
|
24
|
+
@unit = unit
|
16
25
|
end
|
17
26
|
|
18
27
|
def inspect
|
@@ -26,10 +35,10 @@ class Measurement
|
|
26
35
|
def +(obj)
|
27
36
|
case obj
|
28
37
|
when Numeric
|
29
|
-
self.class.new(
|
38
|
+
self.class.new(quantity + obj.to_f, unit)
|
30
39
|
when self.class
|
31
40
|
if obj.unit == unit
|
32
|
-
self.class.new(
|
41
|
+
self.class.new(quantity + obj.quantity, unit)
|
33
42
|
else
|
34
43
|
self + obj.convert_to(unit)
|
35
44
|
end
|
@@ -41,10 +50,10 @@ class Measurement
|
|
41
50
|
def -(obj)
|
42
51
|
case obj
|
43
52
|
when Numeric
|
44
|
-
self.class.new(
|
53
|
+
self.class.new(quantity - obj.to_f, unit)
|
45
54
|
when self.class
|
46
55
|
if obj.unit == unit
|
47
|
-
self.class.new(
|
56
|
+
self.class.new(quantity - obj.quantity, unit)
|
48
57
|
else
|
49
58
|
self - obj.convert_to(unit)
|
50
59
|
end
|
@@ -56,10 +65,10 @@ class Measurement
|
|
56
65
|
def *(obj)
|
57
66
|
case obj
|
58
67
|
when Numeric
|
59
|
-
self.class.new(
|
68
|
+
self.class.new(quantity * obj.to_f, unit)
|
60
69
|
when self.class
|
61
70
|
if obj.unit == unit
|
62
|
-
self.class.new(
|
71
|
+
self.class.new(quantity * obj.quantity, unit)
|
63
72
|
else
|
64
73
|
self * obj.convert_to(unit)
|
65
74
|
end
|
@@ -71,10 +80,10 @@ class Measurement
|
|
71
80
|
def /(obj)
|
72
81
|
case obj
|
73
82
|
when Numeric
|
74
|
-
self.class.new(
|
83
|
+
self.class.new(quantity / obj.to_f, unit)
|
75
84
|
when self.class
|
76
85
|
if obj.unit == unit
|
77
|
-
self.class.new(
|
86
|
+
self.class.new(quantity / obj.quantity, unit)
|
78
87
|
else
|
79
88
|
self / obj.convert_to(unit)
|
80
89
|
end
|
@@ -86,7 +95,7 @@ class Measurement
|
|
86
95
|
def **(obj)
|
87
96
|
case obj
|
88
97
|
when Numeric
|
89
|
-
self.class.new(
|
98
|
+
self.class.new(quantity ** obj.to_f, unit)
|
90
99
|
else
|
91
100
|
raise ArgumentError, "Invalid arithmetic: #{self} ** #{obj}"
|
92
101
|
end
|
@@ -105,7 +114,7 @@ class Measurement
|
|
105
114
|
conversion = @unit.conversion(unit.name)
|
106
115
|
raise ArgumentError, "Invalid conversion: '#@unit' to '#{unit.name}'" unless conversion
|
107
116
|
|
108
|
-
self.class.new(
|
117
|
+
self.class.new(conversion.call(@quantity), unit.name)
|
109
118
|
end
|
110
119
|
|
111
120
|
def convert_to!(unit_name)
|
@@ -120,7 +129,33 @@ class Measurement
|
|
120
129
|
end
|
121
130
|
|
122
131
|
def self.parse(str = '0')
|
123
|
-
|
132
|
+
str = str.strip
|
133
|
+
|
134
|
+
if str =~ COMPLEX_REGEX
|
135
|
+
real, imaginary, unit_name = str.scan(COMPLEX_REGEX).first
|
136
|
+
quantity = Complex(real.to_f, imaginary.to_f).to_f
|
137
|
+
elsif str =~ SCIENTIFIC_REGEX
|
138
|
+
whole, unit_name = str.scan(SCIENTIFIC_REGEX).first
|
139
|
+
quantity = whole.to_f
|
140
|
+
elsif str =~ RATIONAL_REGEX
|
141
|
+
whole, _, numerator, denominator, unit_name = str.scan(RATIONAL_REGEX).first
|
142
|
+
|
143
|
+
if numerator && denominator
|
144
|
+
numerator = numerator.to_f + (denominator.to_f * whole.to_f)
|
145
|
+
denominator = denominator.to_f
|
146
|
+
quantity = Rational(numerator, denominator).to_f
|
147
|
+
else
|
148
|
+
quantity = whole.to_f
|
149
|
+
end
|
150
|
+
else
|
151
|
+
raise ArgumentError, "Unable to parse: '#{str}'"
|
152
|
+
end
|
153
|
+
|
154
|
+
unit_name ||= 'count'
|
155
|
+
unit = units[unit_name.strip.downcase]
|
156
|
+
raise ArgumentError, "Invalid unit: '#{unit_name}'" unless unit
|
157
|
+
|
158
|
+
new(quantity, unit)
|
124
159
|
end
|
125
160
|
|
126
161
|
def self.define(unit_name, &block)
|
@@ -128,29 +163,6 @@ class Measurement
|
|
128
163
|
unit.aliases.each { |a| @units[a.downcase] = unit }
|
129
164
|
end
|
130
165
|
|
131
|
-
private
|
132
|
-
|
133
|
-
def parse(str)
|
134
|
-
value = str.strip
|
135
|
-
|
136
|
-
quantity, unit_name = value.split(/\s+/, 2)
|
137
|
-
unit_name ||= 'count'
|
138
|
-
raise ArgumentError, "Missing quantity: '#{str}'" if !quantity || quantity.empty?
|
139
|
-
|
140
|
-
@unit = self.class.units[unit_name.downcase]
|
141
|
-
raise ArgumentError, "Invalid unit: '#{unit_name}'" unless @unit
|
142
|
-
|
143
|
-
if quantity =~ COMPLEX_NUMBER
|
144
|
-
real, imaginary = quantity.scan(COMPLEX_NUMBER).first
|
145
|
-
@quantity = Complex(real.to_f, imaginary.to_f).to_f
|
146
|
-
elsif quantity =~ RATIONAL_NUMBER
|
147
|
-
numerator, denominator = quantity.scan(RATIONAL_NUMBER).first
|
148
|
-
@quantity = Rational(numerator.to_i, denominator.to_i).to_f
|
149
|
-
else
|
150
|
-
@quantity = quantity.to_f
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
166
|
define(:count) do |unit|
|
155
167
|
unit.convert_to(:dozen) { |value| value / 12.0 }
|
156
168
|
end
|
data/ruby-measurement.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |gem|
|
|
10
10
|
gem.email = 'matt.huggins@gmail.com'
|
11
11
|
gem.description = 'Simple gem for calculating and converting measurements'
|
12
12
|
gem.summary = 'Simple gem for calculating and converting measurements'
|
13
|
-
gem.homepage = 'https://github.com/mhuggins/measurement'
|
13
|
+
gem.homepage = 'https://github.com/mhuggins/ruby-measurement'
|
14
14
|
|
15
15
|
gem.files = `git ls-files`.split($/)
|
16
16
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-measurement
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2013-01-22 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement: &
|
16
|
+
requirement: &2156250560 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2156250560
|
25
25
|
description: Simple gem for calculating and converting measurements
|
26
26
|
email: matt.huggins@gmail.com
|
27
27
|
executables: []
|
@@ -51,7 +51,7 @@ files:
|
|
51
51
|
- lib/ruby-measurement/version.rb
|
52
52
|
- ruby-measurement.gemspec
|
53
53
|
- tasks/debug.rake
|
54
|
-
homepage: https://github.com/mhuggins/measurement
|
54
|
+
homepage: https://github.com/mhuggins/ruby-measurement
|
55
55
|
licenses: []
|
56
56
|
post_install_message:
|
57
57
|
rdoc_options: []
|