general_units 0.0.4 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/general_units.rb +8 -0
- data/lib/general_units/arithmetics/methods.rb +28 -0
- data/lib/general_units/derivatives/box.rb +132 -66
- data/lib/general_units/derivatives/box/packer.rb +52 -0
- data/lib/general_units/helpers/action_view_extension.rb +2 -2
- data/lib/general_units/models/active_record_extension.rb +7 -7
- data/lib/general_units/numeric.rb +4 -0
- data/lib/general_units/units/base/measurement.rb +185 -0
- data/lib/general_units/units/base/unit.rb +36 -0
- data/lib/general_units/units/length.rb +15 -65
- data/lib/general_units/units/volume.rb +20 -0
- data/lib/general_units/units/weight.rb +11 -66
- data/lib/general_units/version.rb +1 -1
- metadata +7 -3
- data/lib/general_units/units/arithmetics/methods.rb +0 -152
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7bb73e1c7d4e5f31b9e497ed16286044be1bd8db
|
4
|
+
data.tar.gz: 1c48246254178ba001ca32f74470b0349aa3aef6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50ed29c361c9264f312f7c258d7d2e990d670b39490abbf139b5014e4d20f9896880a2f7515792aaa370ea01095bbafdd6005a80950a57d69d090d623ef2f611
|
7
|
+
data.tar.gz: fb25b41770e84fa70242d47a65b781c6878773aebe6737fa2efb21c0d08464ed060248a4cb53c7ba4f74fd98a37aa38b2b97acb4065df666e045da1d28857c85
|
data/lib/general_units.rb
CHANGED
@@ -2,6 +2,7 @@ require "general_units/version"
|
|
2
2
|
|
3
3
|
module GeneralUnits
|
4
4
|
def self.load!
|
5
|
+
load_arithmetics!
|
5
6
|
load_units!
|
6
7
|
load_numeric!
|
7
8
|
load_derivatives!
|
@@ -9,9 +10,16 @@ module GeneralUnits
|
|
9
10
|
require 'general_units/railtie'
|
10
11
|
end
|
11
12
|
|
13
|
+
def self.load_arithmetics!
|
14
|
+
require 'general_units/arithmetics/methods'
|
15
|
+
end
|
16
|
+
|
12
17
|
def self.load_units!
|
18
|
+
require 'general_units/units/base/measurement'
|
19
|
+
require 'general_units/units/base/unit'
|
13
20
|
require 'general_units/units/weight'
|
14
21
|
require 'general_units/units/length'
|
22
|
+
require 'general_units/units/volume'
|
15
23
|
end
|
16
24
|
|
17
25
|
def self.load_numeric!
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module GeneralUnits
|
2
|
+
|
3
|
+
module Arithmetics
|
4
|
+
def self.two_factors_of(number)
|
5
|
+
if (number = number.to_i) && (number > 1)
|
6
|
+
primes, powers = number.prime_division.transpose
|
7
|
+
exponents = powers.map {|i| (0..i).to_a}
|
8
|
+
divisors = exponents.shift.product(*exponents).map do |powers|
|
9
|
+
primes.zip(powers).map {|prime, power| prime ** power}.inject(:*)
|
10
|
+
end
|
11
|
+
divisors.sort.map {|div| [div, number/div]}
|
12
|
+
else
|
13
|
+
[]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.three_factors_of(number)
|
18
|
+
export = []
|
19
|
+
two_factors_of(number).each do |factors|
|
20
|
+
two_factors_of(factors[1]).each do |next_factors|
|
21
|
+
export << [factors[0]] + next_factors
|
22
|
+
end
|
23
|
+
end
|
24
|
+
export
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
|
-
require '
|
1
|
+
require 'prime'
|
2
|
+
require 'general_units/derivatives/box/packer'
|
2
3
|
|
3
4
|
module GeneralUnits
|
4
5
|
|
@@ -12,8 +13,10 @@ module GeneralUnits
|
|
12
13
|
delegate :hash, :to => :attributes
|
13
14
|
|
14
15
|
def initialize(length = 0, width = 0, height = 0, unit)
|
15
|
-
|
16
|
-
|
16
|
+
if unit = valid_unit(unit)
|
17
|
+
VALUES.each {|v| instance_variable_set(:"@#{v}", validate_dimension_value(eval(v), unit))}
|
18
|
+
@unit = unit
|
19
|
+
end
|
17
20
|
end
|
18
21
|
|
19
22
|
def attributes
|
@@ -25,11 +28,11 @@ module GeneralUnits
|
|
25
28
|
end
|
26
29
|
|
27
30
|
def amount
|
28
|
-
|
31
|
+
volume.amount
|
29
32
|
end
|
30
33
|
|
31
34
|
def volume
|
32
|
-
length * width * height
|
35
|
+
Volume.new(length * width * height, :"cubic_#{unit.code}")
|
33
36
|
end
|
34
37
|
|
35
38
|
def has_space?
|
@@ -44,33 +47,50 @@ module GeneralUnits
|
|
44
47
|
values.map {|d| d.to_s(round)}.join("x")
|
45
48
|
end
|
46
49
|
|
47
|
-
def formatted(round = nil)
|
48
|
-
|
50
|
+
def formatted(round = nil, &block)
|
51
|
+
if block_given?
|
52
|
+
yield to_s(round), unit
|
53
|
+
else
|
54
|
+
"#{to_s(round)} #{unit.short}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_volume
|
59
|
+
volume
|
49
60
|
end
|
50
61
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
62
|
+
def two_max_values
|
63
|
+
sorted = values.sort.reverse
|
64
|
+
sorted.first(2)
|
65
|
+
end
|
66
|
+
|
67
|
+
def max_face
|
68
|
+
two_max_values[0] * two_max_values[1]
|
69
|
+
end
|
70
|
+
|
71
|
+
def inspect
|
72
|
+
"<#{self.class.name} length=#{length} width=#{width} height=#{height} unit=#{unit}>"
|
54
73
|
end
|
55
74
|
|
56
75
|
def same_size?(other_object)
|
57
|
-
other_object =
|
76
|
+
other_object = validate_box(other_object)
|
58
77
|
eval VALUES.permutation.to_a.map {|values_names| "(length == other_object.#{values_names[0]} && width == other_object.#{values_names[1]} && height == other_object.#{values_names[2]})"}.join("||")
|
59
78
|
end
|
60
79
|
|
61
80
|
def includes?(other_object)
|
62
|
-
other_object =
|
81
|
+
other_object = validate_box(other_object)
|
63
82
|
eval VALUES.permutation.to_a.map {|values_names| "(length >= other_object.#{values_names[0]} && width >= other_object.#{values_names[1]} && height >= other_object.#{values_names[2]})"}.join("||")
|
64
83
|
end
|
65
84
|
|
66
85
|
### ARITHMETICS START ###
|
86
|
+
delegate :<=>, :<, :>, :<=, :>=, :positive?, :negative?, :div, :divmod, :modulo, :%, :remainder, :abs, :zero?, :nonzero?, :coerce, :to => :volume
|
67
87
|
|
68
88
|
def -@
|
69
89
|
Box.new(*values.map {|v| -v}, unit)
|
70
90
|
end
|
71
91
|
|
72
92
|
def ==(other_object)
|
73
|
-
other_object =
|
93
|
+
other_object = validate_box(other_object)
|
74
94
|
length == other_object.length && width == other_object.width && height == other_object.height
|
75
95
|
rescue
|
76
96
|
false
|
@@ -79,53 +99,11 @@ module GeneralUnits
|
|
79
99
|
def eql?(other_object)
|
80
100
|
self == other_object
|
81
101
|
end
|
82
|
-
|
83
|
-
def <=>(other_object)
|
84
|
-
other_object = validate_capacity_or_length(other_object)
|
85
|
-
volume <=> case other_object
|
86
|
-
when Length then other_object
|
87
|
-
when Box then other_object.volume
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def >(other_object)
|
92
|
-
other_object = validate_capacity_or_length(other_object)
|
93
|
-
volume > case other_object
|
94
|
-
when Length then other_object
|
95
|
-
when Box then other_object.volume
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def <(other_object)
|
100
|
-
other_object = validate_capacity_or_length(other_object)
|
101
|
-
volume < case other_object
|
102
|
-
when Length then other_object
|
103
|
-
when Box then other_object.volume
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def >=(other_object)
|
108
|
-
other_object = validate_capacity_or_length(other_object)
|
109
|
-
volume >= case other_object
|
110
|
-
when Length then other_object
|
111
|
-
when Box then other_object.volume
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def <=(other_object)
|
116
|
-
other_object = validate_capacity_or_length(other_object)
|
117
|
-
volume <= case other_object
|
118
|
-
when Length then other_object
|
119
|
-
when Box then other_object.volume
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
delegate :positive?, :negative?, :to => :volume
|
124
102
|
|
125
103
|
def +(other_object)
|
126
104
|
other_object = validate_capacity_or_length(other_object)
|
127
105
|
case other_object
|
128
|
-
when Length then Box.new(*values.map {|v| v + other_object/3}, unit)
|
106
|
+
when Length, Volume then Box.new(*values.map {|v| v + other_object/3}, unit)
|
129
107
|
when Box then Box.new(*VALUES.map {|v| eval(v) + other_object.send(v)}, unit)
|
130
108
|
end
|
131
109
|
end
|
@@ -133,7 +111,7 @@ module GeneralUnits
|
|
133
111
|
def -(other_object)
|
134
112
|
other_object = validate_capacity_or_length(other_object)
|
135
113
|
case other_object
|
136
|
-
when Length then Box.new(*values.map {|v| v - other_object/3}, unit)
|
114
|
+
when Length, Volume then Box.new(*values.map {|v| v - other_object/3}, unit)
|
137
115
|
when Box then Box.new(*VALUES.map {|v| eval(v) - other_object.send(v)}, unit)
|
138
116
|
end
|
139
117
|
end
|
@@ -141,7 +119,7 @@ module GeneralUnits
|
|
141
119
|
def *(other_object)
|
142
120
|
other_object = validate_capacity_or_length(other_object)
|
143
121
|
case other_object
|
144
|
-
when Length then Box.new(*values.map {|v| v * other_object}, unit)
|
122
|
+
when Length, Volume then Box.new(*values.map {|v| v * other_object}, unit)
|
145
123
|
when Box then Box.new(*VALUES.map {|v| eval(v) * other_object.send(v)}, unit)
|
146
124
|
end
|
147
125
|
end
|
@@ -149,22 +127,109 @@ module GeneralUnits
|
|
149
127
|
def /(other_object)
|
150
128
|
other_object = validate_capacity_or_length(other_object)
|
151
129
|
case other_object
|
152
|
-
when Length then Box.new(*values.map {|v| v / other_object}, unit)
|
130
|
+
when Length, Volume then Box.new(*values.map {|v| v / other_object}, unit)
|
153
131
|
when Box then Box.new(*VALUES.map {|v| eval(v) / other_object.send(v)}, unit)
|
154
132
|
end
|
155
133
|
end
|
134
|
+
|
135
|
+
### ARITHMETICS END ###
|
156
136
|
|
157
|
-
|
137
|
+
def multiplicator(sum)
|
138
|
+
GeneralUnits::Arithmetics.three_factors_of(sum).map do |v|
|
139
|
+
Box.new(v[0]*length, v[1]*width, v[2]*height, unit)
|
140
|
+
end
|
141
|
+
end
|
158
142
|
|
159
|
-
|
143
|
+
def multiply_to_strong_box(sum)
|
144
|
+
multiplicator(sum).min_by {|box| box.values.max - box.values.min}
|
145
|
+
end
|
146
|
+
|
147
|
+
def multiply_to_optimal(sum)
|
148
|
+
if sum.odd?
|
149
|
+
[multiply_to_strong_box(sum-1), self]
|
150
|
+
else
|
151
|
+
[multiply_to_strong_box(sum)]
|
152
|
+
end.compact
|
153
|
+
end
|
154
|
+
|
155
|
+
def concat_with(other_box, &block)
|
156
|
+
#other_box = other_box.convert_to(unit)
|
157
|
+
|
158
|
+
length_1, width_1, height_1 = *values.sort.reverse
|
159
|
+
length_2, width_2, height_2 = *other_box.values.sort.reverse
|
160
|
+
|
161
|
+
x1 = (length_1 - length_2).abs
|
162
|
+
length = [length_1, length_2].max
|
163
|
+
|
164
|
+
x2 = (width_1 - width_2).abs
|
165
|
+
width = [width_1, width_2].max
|
166
|
+
|
167
|
+
height = height_1 + height_2
|
168
|
+
|
169
|
+
if x1 > 0
|
170
|
+
y1 = width
|
171
|
+
z1 = length_1 > length_2 ? height_2 : height_1
|
172
|
+
yield(Box.new(x1, y1, z1, unit)) if block_given?
|
173
|
+
end
|
174
|
+
|
175
|
+
if x2 > 0
|
176
|
+
y2 = ((length_1 > length_2) && (width_1 > width_2)) ? length-x1 : length
|
177
|
+
z2 = width_1 > width_2 ? height_2 : height_1
|
178
|
+
yield(Box.new(x2, y2, z2, unit)) if block_given?
|
179
|
+
end
|
180
|
+
|
181
|
+
Box.new(length, width, height, unit).convert_to(unit)
|
182
|
+
end
|
183
|
+
|
184
|
+
def estimated_spaces_with(other_box, &block)
|
185
|
+
#other_box = other_box.convert_to(unit)
|
186
|
+
|
187
|
+
if includes?(other_box)
|
188
|
+
length_1, width_1, height_1 = *values.sort.reverse
|
189
|
+
length_2, width_2, height_2 = *other_box.values.sort.reverse
|
190
|
+
|
191
|
+
estimated_spaces = []
|
192
|
+
|
193
|
+
x1 = (length_1 - length_2).abs
|
194
|
+
if x1 > 0
|
195
|
+
space1 = Box.new(x1, width_1, height_1, unit)
|
196
|
+
estimated_spaces << space1
|
197
|
+
yield(space1) if block_given?
|
198
|
+
end
|
199
|
+
|
200
|
+
x2 = (width_1 - width_2).abs
|
201
|
+
if x2 > 0
|
202
|
+
space2 = Box.new(length_1 - x1, x2, height_1, unit)
|
203
|
+
estimated_spaces << space2
|
204
|
+
yield(space2) if block_given?
|
205
|
+
end
|
206
|
+
|
207
|
+
x3 = (height_1 - height_2).abs
|
208
|
+
if x3 > 0
|
209
|
+
space3 = Box.new(length_2, width_2, x3, unit)
|
210
|
+
estimated_spaces << space3
|
211
|
+
yield(space3) if block_given?
|
212
|
+
end
|
213
|
+
|
214
|
+
estimated_spaces
|
215
|
+
end
|
216
|
+
end
|
160
217
|
|
161
218
|
private
|
219
|
+
|
220
|
+
def valid_unit(unit)
|
221
|
+
unit_object = case unit
|
222
|
+
when String, Symbol then Length.units.find {|u| u.code.to_s == unit.to_s}
|
223
|
+
when Base::Unit then unit
|
224
|
+
end
|
225
|
+
unit_object || raise(TypeError, "Unprocessable unit #{unit.inspect}")
|
226
|
+
end
|
162
227
|
|
163
|
-
def
|
228
|
+
def validate_dimension_value(val, unit)
|
164
229
|
val.is_a?(Length) ? val.convert_to(unit) : Length.new(val, unit)
|
165
230
|
end
|
166
231
|
|
167
|
-
def
|
232
|
+
def validate_box(val)
|
168
233
|
case val
|
169
234
|
when Box then val.convert_to(unit)
|
170
235
|
else raise(TypeError, "Box required, #{val.class} passed.")
|
@@ -173,9 +238,10 @@ module GeneralUnits
|
|
173
238
|
|
174
239
|
def validate_capacity_or_length(val)
|
175
240
|
case val
|
176
|
-
when Box
|
177
|
-
when
|
178
|
-
|
241
|
+
when Box then val.convert_to(unit)
|
242
|
+
when Volume then val.convert_to(volume.unit.code)
|
243
|
+
when Length, Numeric then val.to_volume(volume.unit.code)
|
244
|
+
else raise(TypeError, "Box or Volume or Numeric required, #{val.class} passed.")
|
179
245
|
end
|
180
246
|
end
|
181
247
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module GeneralUnits
|
2
|
+
class Box
|
3
|
+
|
4
|
+
class Packer
|
5
|
+
attr_reader :boxes, :gaps, :coupled, :gaps_used, :rotated
|
6
|
+
|
7
|
+
def initialize(*boxes)
|
8
|
+
@boxes = boxes.sort_by(&:max_face).reverse
|
9
|
+
@coupled = @boxes.first # first box - biggest
|
10
|
+
@gaps = []
|
11
|
+
@gaps_used = [] # for test
|
12
|
+
@rotated = 0 # if height > current length
|
13
|
+
pack!
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
inspect
|
18
|
+
end
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
"<#{self.class.name} boxes=#{boxes.size} gaps=#{gaps.size} used=#{gaps_used.size} coupled=#{coupled}>"
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def pack!
|
27
|
+
boxes[1..-1].each do |box|
|
28
|
+
unless use_gap_for(box)
|
29
|
+
@coupled = coupled.concat_with(box) {|r| @gaps << r}
|
30
|
+
# if coupled.height > coupled.length
|
31
|
+
# @rotated += 1
|
32
|
+
# end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
coupled
|
36
|
+
end
|
37
|
+
|
38
|
+
def use_gap_for(box)
|
39
|
+
gap = @gaps.find_all {|g| g.includes?(box)}.min_by {|g| g.volume - box.volume}
|
40
|
+
if gap && gap.estimated_spaces_with(box) {|r| @gaps << r}
|
41
|
+
@gaps.delete_if {|r| r.object_id == gap.object_id}
|
42
|
+
@gaps_used << box
|
43
|
+
true
|
44
|
+
else
|
45
|
+
false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -7,11 +7,11 @@ module GeneralUnits
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def weight_units_for_select
|
10
|
-
Weight
|
10
|
+
Weight.units.map {|u| [u.name, u.code]}
|
11
11
|
end
|
12
12
|
|
13
13
|
def length_units_for_select
|
14
|
-
Length
|
14
|
+
Length.units.map {|u| [u.name, u.code]}
|
15
15
|
end
|
16
16
|
|
17
17
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module GeneralUnits
|
2
2
|
|
3
3
|
module ActiveRecordExtension
|
4
|
-
extend ActiveSupport::Concern
|
4
|
+
extend ::ActiveSupport::Concern
|
5
5
|
|
6
6
|
module ClassMethods
|
7
7
|
|
@@ -17,12 +17,12 @@ module GeneralUnits
|
|
17
17
|
self._has_weight[prefix][:default_unit] = default_unit = options[:default_unit]||:kilogram
|
18
18
|
self._has_weight[prefix][:default_unit_method] = default_unit_method = options[:default_unit_method]||:"deafult_#{prefix}_unit"
|
19
19
|
|
20
|
-
|
20
|
+
validates_inclusion_of unit_field, :in => Weight.units.map {|u| u.code.to_s}, :if => Proc.new {|o| o.send(amount_field).present?}
|
21
21
|
|
22
22
|
class_eval <<-EOV
|
23
23
|
|
24
24
|
def #{unit_field}=(value)
|
25
|
-
if value.to_sym.in?(GeneralUnits::Weight
|
25
|
+
if value.to_sym.in?(GeneralUnits::Weight.units.map(&:code))
|
26
26
|
super(value.to_s)
|
27
27
|
else
|
28
28
|
raise ArgumentError, "Unprocessable unit: \#{value.inspect\}"
|
@@ -77,12 +77,12 @@ module GeneralUnits
|
|
77
77
|
self._has_length[prefix][:default_unit] = default_unit = options[:default_unit]||:centimeter
|
78
78
|
self._has_length[prefix][:default_unit_method] = default_unit_method = options[:default_unit_method]||:"deafult_#{prefix}_unit"
|
79
79
|
|
80
|
-
|
80
|
+
validates_inclusion_of unit_field, :in => Length.units.map {|u| u.code.to_s}, :if => Proc.new {|o| o.send(amount_field).present?}
|
81
81
|
|
82
82
|
class_eval <<-EOV
|
83
83
|
|
84
84
|
def #{unit_field}=(value)
|
85
|
-
if value.to_sym.in?(GeneralUnits::Length
|
85
|
+
if value.to_sym.in?(GeneralUnits::Length.units.map(&:code))
|
86
86
|
super(value.to_s)
|
87
87
|
else
|
88
88
|
raise ArgumentError, "Unprocessable unit: \#{value.inspect\}"
|
@@ -140,12 +140,12 @@ module GeneralUnits
|
|
140
140
|
self._has_box[prefix][:default_unit] = default_unit = options[:default_unit]||:centimeter
|
141
141
|
self._has_box[prefix][:default_unit_method] = default_unit_method = options[:default_unit_method]||:"deafult_#{prefix}_unit"
|
142
142
|
|
143
|
-
|
143
|
+
validates_inclusion_of unit_field, :in => Length.units.map {|u| u.code.to_s}, :if => Proc.new {|o| o.send(length_field).present? || o.send(width_field).present? || o.send(height_field).present?}
|
144
144
|
|
145
145
|
class_eval <<-EOV
|
146
146
|
|
147
147
|
def #{unit_field}=(value)
|
148
|
-
if value.to_sym.in?(GeneralUnits::Length
|
148
|
+
if value.to_sym.in?(GeneralUnits::Length.units.map(&:code))
|
149
149
|
super(value.to_s)
|
150
150
|
else
|
151
151
|
raise ArgumentError, "Unprocessable unit: \#{value.inspect\}"
|
@@ -0,0 +1,185 @@
|
|
1
|
+
module GeneralUnits
|
2
|
+
module Base
|
3
|
+
class Measurement
|
4
|
+
class_attribute :units unless defined?(units)
|
5
|
+
|
6
|
+
attr_reader :amount, :unit
|
7
|
+
delegate :hash, :to => :attributes
|
8
|
+
|
9
|
+
def initialize(amount = 0, unit)
|
10
|
+
if unit = valid_unit?(unit)
|
11
|
+
@amount = amount.try(:to_d)||0.to_d
|
12
|
+
@unit = unit
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def attributes
|
17
|
+
{:amount => amount, :unit => unit}
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s(round = nil)
|
21
|
+
"#{to_f.divmod(1).last == 0 ? to_f.round(0) : to_f.round(round||2)}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def inspect
|
25
|
+
"<#{self.class.name} amount=#{amount} unit=#{unit}>"
|
26
|
+
end
|
27
|
+
|
28
|
+
def formatted(round = nil, &block)
|
29
|
+
if block_given?
|
30
|
+
yield to_s(round), unit
|
31
|
+
else
|
32
|
+
"#{to_s(round)} #{unit.short}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
### ARITHMETICS START ###
|
37
|
+
delegate :to_f, :to_d, :to_i, :round, :to => :amount
|
38
|
+
|
39
|
+
def measurement
|
40
|
+
self.class.name.split("::").last.underscore
|
41
|
+
end
|
42
|
+
|
43
|
+
def -@
|
44
|
+
self.class.new(-amount, unit)
|
45
|
+
end
|
46
|
+
|
47
|
+
def ==(other_object)
|
48
|
+
amount == valid_amount(other_object)
|
49
|
+
rescue NoMethodError
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
53
|
+
def eql?(other_object)
|
54
|
+
self == other_object
|
55
|
+
end
|
56
|
+
|
57
|
+
def <=>(other_object)
|
58
|
+
amount <=> valid_amount(other_object)
|
59
|
+
rescue NoMethodError
|
60
|
+
raise ArgumentError, "Comparison of #{self.class} with #{val.inspect} failed"
|
61
|
+
end
|
62
|
+
|
63
|
+
def >(other_object)
|
64
|
+
amount > valid_amount(other_object)
|
65
|
+
end
|
66
|
+
|
67
|
+
def <(other_object)
|
68
|
+
amount < valid_amount(other_object)
|
69
|
+
end
|
70
|
+
|
71
|
+
def >=(other_object)
|
72
|
+
amount >= valid_amount(other_object)
|
73
|
+
end
|
74
|
+
|
75
|
+
def <=(other_object)
|
76
|
+
amount <= valid_amount(other_object)
|
77
|
+
end
|
78
|
+
|
79
|
+
def positive?
|
80
|
+
self > 0
|
81
|
+
end
|
82
|
+
|
83
|
+
def negative?
|
84
|
+
self < 0
|
85
|
+
end
|
86
|
+
|
87
|
+
def +(other_object)
|
88
|
+
self.class.new(amount + valid_amount(other_object), unit)
|
89
|
+
end
|
90
|
+
|
91
|
+
def -(other_object)
|
92
|
+
self.class.new(amount - valid_amount(other_object), unit)
|
93
|
+
end
|
94
|
+
|
95
|
+
def *(other_object)
|
96
|
+
self.class.new(amount * valid_amount(other_object), unit)
|
97
|
+
end
|
98
|
+
|
99
|
+
def /(other_object)
|
100
|
+
self.class.new(amount / valid_amount(other_object), unit)
|
101
|
+
end
|
102
|
+
|
103
|
+
def div(value)
|
104
|
+
amount.div(value)
|
105
|
+
end
|
106
|
+
|
107
|
+
def divmod(val)
|
108
|
+
if val.is_a?(self.class)
|
109
|
+
divmod_object(val)
|
110
|
+
else
|
111
|
+
divmod_other(val)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def divmod_object(val)
|
116
|
+
amount = val.convert_to(unit).amount
|
117
|
+
quotient, remainder = amount.divmod(amount)
|
118
|
+
[quotient, self.class.new(remainder, unit)]
|
119
|
+
end
|
120
|
+
private :divmod_object
|
121
|
+
|
122
|
+
def divmod_other(val)
|
123
|
+
quotient, remainder = amount.divmod(valid_amount(other_object))
|
124
|
+
[self.class.new(quotient, unit), self.class.new(remainder, unit)]
|
125
|
+
end
|
126
|
+
private :divmod_other
|
127
|
+
|
128
|
+
def modulo(val)
|
129
|
+
divmod(val)[1]
|
130
|
+
end
|
131
|
+
|
132
|
+
def %(val)
|
133
|
+
modulo(val)
|
134
|
+
end
|
135
|
+
|
136
|
+
def remainder(val)
|
137
|
+
if val.is_a?(self.class) && unit != val.unit
|
138
|
+
val = val.convert_to(unit)
|
139
|
+
end
|
140
|
+
|
141
|
+
if (amount < 0 && val < 0) || (amount > 0 && val > 0)
|
142
|
+
self.modulo(val)
|
143
|
+
else
|
144
|
+
self.modulo(val) - (val.is_a?(self.class) ? val : self.class.new(val, unit))
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def abs
|
149
|
+
self.class.new(amount.abs, unit)
|
150
|
+
end
|
151
|
+
|
152
|
+
def zero?
|
153
|
+
amount == 0
|
154
|
+
end
|
155
|
+
|
156
|
+
def nonzero?
|
157
|
+
amount != 0 ? self : nil
|
158
|
+
end
|
159
|
+
|
160
|
+
def coerce(other)
|
161
|
+
[self, other]
|
162
|
+
end
|
163
|
+
### ARITHMETICS END ###
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
def valid_amount(other_object)
|
168
|
+
case other_object
|
169
|
+
when self.class then other_object.convert_to(unit).amount
|
170
|
+
when Numeric then other_object
|
171
|
+
else other_object.send(:"to_#{measurement}").convert_to(unit).amount
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def valid_unit?(unit)
|
176
|
+
unit_object = case unit
|
177
|
+
when String, Symbol then units.find {|u| u.code.to_s == unit.to_s}
|
178
|
+
when Unit then unit
|
179
|
+
end
|
180
|
+
unit_object || raise(TypeError, "Unprocessable unit #{unit.inspect}")
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module GeneralUnits
|
2
|
+
module Base
|
3
|
+
class Unit
|
4
|
+
METRIC_SYSTEMS = [:metric, :english, :american]
|
5
|
+
|
6
|
+
attr_reader :code, :name, :short, :fractional, :system
|
7
|
+
|
8
|
+
def initialize(code, name, short, fractional, system = :metric)
|
9
|
+
@code = code
|
10
|
+
@name = name.to_s
|
11
|
+
@short = short.to_s
|
12
|
+
@fractional = fractional.to_d
|
13
|
+
@system = system.to_sym
|
14
|
+
METRIC_SYSTEMS.each do |s|
|
15
|
+
class_eval do
|
16
|
+
define_method "#{s}?" do
|
17
|
+
self.system == s
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
name
|
25
|
+
end
|
26
|
+
|
27
|
+
def inspect
|
28
|
+
code
|
29
|
+
end
|
30
|
+
|
31
|
+
def system
|
32
|
+
METRIC_SYSTEMS.find {|s| s == @system}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,52 +1,19 @@
|
|
1
|
-
require 'general_units/units/arithmetics/methods'
|
2
|
-
|
3
1
|
module GeneralUnits
|
4
|
-
class Length
|
5
|
-
::GeneralUnits::Arithmetics.extend_class(self)
|
2
|
+
class Length < ::GeneralUnits::Base::Measurement
|
6
3
|
|
7
|
-
class Unit
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(code, name, short, millimeters)
|
11
|
-
@code = code
|
12
|
-
@name = name.to_s
|
13
|
-
@short = short.to_s
|
14
|
-
@millimeters = millimeters.to_d
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_s
|
18
|
-
name
|
19
|
-
end
|
20
|
-
|
21
|
-
def inspect
|
22
|
-
code
|
23
|
-
end
|
4
|
+
class Unit < ::GeneralUnits::Base::Unit
|
5
|
+
alias :millimeters :fractional
|
24
6
|
end
|
25
7
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
attr_reader :amount, :unit
|
37
|
-
delegate :to_f, :to => :amount
|
38
|
-
delegate :hash, :to => :attributes
|
39
|
-
|
40
|
-
def initialize(amount = 0, unit)
|
41
|
-
if unit = valid_unit?(unit)
|
42
|
-
@amount = amount.try(:to_d)||0.to_d
|
43
|
-
@unit = unit
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def attributes
|
48
|
-
{:amount => amount, :unit => unit}
|
49
|
-
end
|
8
|
+
self.units = [Unit.new(:mile_nautical, "Mile (nautical)", "mln", 1852000.0, :english),
|
9
|
+
Unit.new(:mile, "Mile", "ml", 1609344.0, :english),
|
10
|
+
Unit.new(:yard, "Yard", "yrd", 914.4, :english),
|
11
|
+
Unit.new(:foot, "Foot", "ft", 304.8, :english),
|
12
|
+
Unit.new(:inch, "Inch", "in", 25.4, :english),
|
13
|
+
Unit.new(:kilometer, "Kilometer", "km", 1000000.0),
|
14
|
+
Unit.new(:meter, "Meter", "m", 1000.0),
|
15
|
+
Unit.new(:centimeter, "Centimeter", "cm", 10.0),
|
16
|
+
Unit.new(:millimeter, "Millimeter", "mm", 1.0)]
|
50
17
|
|
51
18
|
def convert_to(unit)
|
52
19
|
if convert_unit = valid_unit?(unit)
|
@@ -54,27 +21,10 @@ module GeneralUnits
|
|
54
21
|
Length.new(convert_amount, unit)
|
55
22
|
end
|
56
23
|
end
|
57
|
-
|
58
|
-
def to_s(round = nil)
|
59
|
-
"#{to_f.divmod(1).last == 0 ? to_f.round(0) : to_f.round(round||2)}"
|
60
|
-
end
|
61
24
|
|
62
|
-
def
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
def to_length
|
67
|
-
self
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def valid_unit?(unit)
|
73
|
-
unit_object = case unit
|
74
|
-
when String, Symbol then UNITS.find {|u| u.code.to_s == unit.to_s}
|
75
|
-
when Unit then unit
|
76
|
-
end
|
77
|
-
unit_object || raise(TypeError, "Unprocessable unit #{unit.inspect}")
|
25
|
+
def to_volume(unit_code)
|
26
|
+
volume = GeneralUnits::Volume.new(amount, :"cubic_#{unit.code}")
|
27
|
+
unit_code ? volume.convert_to(unit_code) : volume
|
78
28
|
end
|
79
29
|
|
80
30
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module GeneralUnits
|
2
|
+
class Volume < ::GeneralUnits::Base::Measurement
|
3
|
+
|
4
|
+
class Unit < ::GeneralUnits::Base::Unit
|
5
|
+
alias :cubic_millimeters :fractional
|
6
|
+
end
|
7
|
+
|
8
|
+
self.units = Length.units.map do |unit|
|
9
|
+
Unit.new("cubic_#{unit.code}", "Cubic #{unit.name}", "#{unit.short}", unit.fractional**3, unit.system)
|
10
|
+
end
|
11
|
+
|
12
|
+
def convert_to(unit)
|
13
|
+
if convert_unit = valid_unit?(unit)
|
14
|
+
convert_amount = amount * @unit.cubic_millimeters/convert_unit.cubic_millimeters
|
15
|
+
Volume.new(convert_amount, unit)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -1,51 +1,18 @@
|
|
1
|
-
require 'general_units/units/arithmetics/methods'
|
2
|
-
|
3
1
|
module GeneralUnits
|
4
|
-
class Weight
|
5
|
-
::GeneralUnits::Arithmetics.extend_class(self)
|
2
|
+
class Weight < ::GeneralUnits::Base::Measurement
|
6
3
|
|
7
|
-
class Unit
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(code, name, short, grams)
|
11
|
-
@code = code
|
12
|
-
@name = name.to_s
|
13
|
-
@short = short.to_s
|
14
|
-
@grams = grams.to_d
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_s
|
18
|
-
name
|
19
|
-
end
|
20
|
-
|
21
|
-
def inspect
|
22
|
-
code
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
UNITS = [Unit.new(:short_ton_us, "Short ton (US)", "Sht.", 907184.74),
|
27
|
-
Unit.new(:pound_us, "Pound (US)", "Pnd.", 453.59237),
|
28
|
-
Unit.new(:ounce_us, "Ounce (US)", "Ounce", 28.349523),
|
29
|
-
Unit.new(:stone, "Stone", "Stn", 6350.2932),
|
30
|
-
Unit.new(:long_ton_uk, "Long Ton (UK)", "Lngt.", 1016046.9),
|
31
|
-
Unit.new(:metric_ton, "Metric Ton", "Ton", 1000000.0),
|
32
|
-
Unit.new(:kilogram, "Kilogram", "Kg.", 1000.0),
|
33
|
-
Unit.new(:gram, "Gram", "g.", 1.0)]
|
34
|
-
|
35
|
-
attr_reader :amount, :unit
|
36
|
-
delegate :to_f, :to => :amount
|
37
|
-
delegate :hash, :to => :attributes
|
38
|
-
|
39
|
-
def initialize(amount = 0, unit)
|
40
|
-
if unit = valid_unit?(unit)
|
41
|
-
@amount = amount.try(:to_d)||0.to_d
|
42
|
-
@unit = unit
|
43
|
-
end
|
4
|
+
class Unit < ::GeneralUnits::Base::Unit
|
5
|
+
alias :grams :fractional
|
44
6
|
end
|
45
7
|
|
46
|
-
|
47
|
-
|
48
|
-
|
8
|
+
self.units = [Unit.new(:short_ton_us, "Short ton (US)", "Sht", 907184.74, :american),
|
9
|
+
Unit.new(:pound_us, "Pound (US)", "Pnd", 453.59237, :american),
|
10
|
+
Unit.new(:ounce_us, "Ounce (US)", "Ounce", 28.349523, :american),
|
11
|
+
Unit.new(:stone, "Stone", "Stn", 6350.2932, :english),
|
12
|
+
Unit.new(:long_ton_uk, "Long Ton (UK)", "Lngt", 1016046.9, :english),
|
13
|
+
Unit.new(:metric_ton, "Metric Ton", "Ton", 1000000.0),
|
14
|
+
Unit.new(:kilogram, "Kilogram", "Kg", 1000.0),
|
15
|
+
Unit.new(:gram, "Gram", "g.", 1.0)]
|
49
16
|
|
50
17
|
def convert_to(unit)
|
51
18
|
if convert_unit = valid_unit?(unit)
|
@@ -53,28 +20,6 @@ module GeneralUnits
|
|
53
20
|
Weight.new(convert_amount, unit)
|
54
21
|
end
|
55
22
|
end
|
56
|
-
|
57
|
-
def to_s(round = nil)
|
58
|
-
"#{to_f.divmod(1).last == 0 ? to_f.round(0) : to_f.round(round||2)}"
|
59
|
-
end
|
60
23
|
|
61
|
-
def formatted(round = nil)
|
62
|
-
"#{to_s(round)} #{unit.short}"
|
63
|
-
end
|
64
|
-
|
65
|
-
def to_weight
|
66
|
-
self
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def valid_unit?(unit)
|
72
|
-
unit_object = case unit
|
73
|
-
when String, Symbol then UNITS.find {|u| u.code.to_s == unit.to_s}
|
74
|
-
when Unit then unit
|
75
|
-
end
|
76
|
-
unit_object || raise(TypeError, "Unprocessable unit #{unit.inspect}")
|
77
|
-
end
|
78
|
-
|
79
24
|
end
|
80
25
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: general_units
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Valery Kvon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: i18n
|
@@ -38,14 +38,18 @@ files:
|
|
38
38
|
- Rakefile
|
39
39
|
- general_units.gemspec
|
40
40
|
- lib/general_units.rb
|
41
|
+
- lib/general_units/arithmetics/methods.rb
|
41
42
|
- lib/general_units/derivatives/box.rb
|
43
|
+
- lib/general_units/derivatives/box/packer.rb
|
42
44
|
- lib/general_units/engine.rb
|
43
45
|
- lib/general_units/helpers/action_view_extension.rb
|
44
46
|
- lib/general_units/models/active_record_extension.rb
|
45
47
|
- lib/general_units/numeric.rb
|
46
48
|
- lib/general_units/railtie.rb
|
47
|
-
- lib/general_units/units/
|
49
|
+
- lib/general_units/units/base/measurement.rb
|
50
|
+
- lib/general_units/units/base/unit.rb
|
48
51
|
- lib/general_units/units/length.rb
|
52
|
+
- lib/general_units/units/volume.rb
|
49
53
|
- lib/general_units/units/weight.rb
|
50
54
|
- lib/general_units/version.rb
|
51
55
|
homepage: http://vkvon.ru/projects/general_units
|
@@ -1,152 +0,0 @@
|
|
1
|
-
module GeneralUnits
|
2
|
-
|
3
|
-
module Arithmetics
|
4
|
-
def self.extend_class(klass)
|
5
|
-
unit_name = klass.name.split("::").last.underscore
|
6
|
-
klass.class_eval <<-EOV
|
7
|
-
delegate :to_f, :to_d, :to_i, :to => :amount
|
8
|
-
|
9
|
-
def -@
|
10
|
-
#{klass.name}.new(-amount, unit)
|
11
|
-
end
|
12
|
-
|
13
|
-
def ==(other_object)
|
14
|
-
other_object = other_object.to_#{unit_name} unless other_object.is_a?(#{klass.name})
|
15
|
-
amount == other_object.convert_to(unit).amount
|
16
|
-
rescue NoMethodError
|
17
|
-
false
|
18
|
-
end
|
19
|
-
|
20
|
-
def eql?(other_object)
|
21
|
-
self == other_object
|
22
|
-
end
|
23
|
-
|
24
|
-
def <=>(val)
|
25
|
-
val = val.to_#{unit_name}
|
26
|
-
unless amount == 0 || val.amount == 0 || unit == val.unit
|
27
|
-
val = val.convert_to(unit)
|
28
|
-
end
|
29
|
-
amount <=> val.amount
|
30
|
-
rescue NoMethodError
|
31
|
-
raise ArgumentError, "Comparison of #{self.class} with \#{val.inspect} failed"
|
32
|
-
end
|
33
|
-
|
34
|
-
def >(other_object)
|
35
|
-
other_object = other_object.is_a?(#{klass.name}) ? other_object.convert_to(unit) : other_object.to_#{unit_name}
|
36
|
-
amount > other_object.amount
|
37
|
-
end
|
38
|
-
|
39
|
-
def <(other_object)
|
40
|
-
other_object = other_object.is_a?(#{klass.name}) ? other_object.convert_to(unit) : other_object.to_#{unit_name}
|
41
|
-
amount < other_object.amount
|
42
|
-
end
|
43
|
-
|
44
|
-
def >=(other_object)
|
45
|
-
other_object = other_object.is_a?(#{klass.name}) ? other_object.convert_to(unit) : other_object.to_#{unit_name}
|
46
|
-
amount >= other_object.amount
|
47
|
-
end
|
48
|
-
|
49
|
-
def <=(other_object)
|
50
|
-
other_object = other_object.is_a?(#{klass.name}) ? other_object.convert_to(unit) : other_object.to_#{unit_name}
|
51
|
-
amount <= other_object.amount
|
52
|
-
end
|
53
|
-
|
54
|
-
def positive?
|
55
|
-
amount > 0
|
56
|
-
end
|
57
|
-
|
58
|
-
def negative?
|
59
|
-
amount < 0
|
60
|
-
end
|
61
|
-
|
62
|
-
def +(other_object)
|
63
|
-
other_object = other_object.is_a?(#{klass.name}) ? other_object.convert_to(unit) : other_object.to_#{unit_name}
|
64
|
-
#{klass.name}.new(amount + other_object.amount, unit)
|
65
|
-
end
|
66
|
-
|
67
|
-
def -(other_object)
|
68
|
-
other_object = other_object.is_a?(#{klass.name}) ? other_object.convert_to(unit) : other_object.to_#{unit_name}
|
69
|
-
#{klass.name}.new(amount - other_object.amount, unit)
|
70
|
-
end
|
71
|
-
|
72
|
-
def *(value)
|
73
|
-
case value
|
74
|
-
when Numeric then #{klass.name}.new(amount * value, unit)
|
75
|
-
when #{klass.name} then #{klass.name}.new(amount * value.convert_to(unit).amount, unit)
|
76
|
-
else raise ArgumentError, "Can't multiply a #{klass.name} by a \#{value.class.name}'s value"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def /(value)
|
81
|
-
case value
|
82
|
-
when Numeric then #{klass.name}.new(amount / value, unit)
|
83
|
-
when #{klass.name} then #{klass.name}.new(amount / value.convert_to(unit).amount, unit)
|
84
|
-
else raise ArgumentError, "Can't divide a #{klass.name} by a \#{value.class.name}'s value"
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def div(value)
|
89
|
-
amount.div(value)
|
90
|
-
end
|
91
|
-
|
92
|
-
def divmod(val)
|
93
|
-
if val.is_a?(#{klass.name})
|
94
|
-
divmod_object(val)
|
95
|
-
else
|
96
|
-
divmod_other(val)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def divmod_object(val)
|
101
|
-
amount = val.convert_to(unit).amount
|
102
|
-
quotient, remainder = amount.divmod(amount)
|
103
|
-
[quotient, #{klass.name}.new(remainder, unit)]
|
104
|
-
end
|
105
|
-
private :divmod_object
|
106
|
-
|
107
|
-
def divmod_other(val)
|
108
|
-
quotient, remainder = amount.divmod(val.to_#{unit_name}(unit).amount)
|
109
|
-
[#{klass.name}.new(quotient, unit), #{klass.name}.new(remainder, unit)]
|
110
|
-
end
|
111
|
-
private :divmod_other
|
112
|
-
|
113
|
-
def modulo(val)
|
114
|
-
divmod(val)[1]
|
115
|
-
end
|
116
|
-
|
117
|
-
def %(val)
|
118
|
-
modulo(val)
|
119
|
-
end
|
120
|
-
|
121
|
-
def remainder(val)
|
122
|
-
if val.is_a?(#{klass.name}) && unit != val.unit
|
123
|
-
val = val.convert_to(unit)
|
124
|
-
end
|
125
|
-
|
126
|
-
if (amount < 0 && val < 0) || (amount > 0 && val > 0)
|
127
|
-
self.modulo(val)
|
128
|
-
else
|
129
|
-
self.modulo(val) - (val.is_a?(#{klass.name}) ? val : #{klass.name}.new(val, unit))
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def abs
|
134
|
-
#{klass.name}.new(amount.abs, unit)
|
135
|
-
end
|
136
|
-
|
137
|
-
def zero?
|
138
|
-
amount == 0
|
139
|
-
end
|
140
|
-
|
141
|
-
def nonzero?
|
142
|
-
amount != 0 ? self : nil
|
143
|
-
end
|
144
|
-
|
145
|
-
def coerce(other)
|
146
|
-
[self, other]
|
147
|
-
end
|
148
|
-
EOV
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
end
|