sy 2.1.2 → 2.1.4
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.
- checksums.yaml +4 -4
- data/lib/sy.rb +4 -44
- data/lib/sy/absolute_magnitude.rb +8 -31
- data/lib/sy/composition.rb +7 -22
- data/lib/sy/dimension.rb +1 -3
- data/lib/sy/expressible_in_units.rb +5 -25
- data/lib/sy/fixed_assets_of_the_module.rb +6 -16
- data/lib/sy/magnitude.rb +1 -130
- data/lib/sy/mapping.rb +4 -11
- data/lib/sy/matrix.rb +1 -3
- data/lib/sy/measure.rb +3 -8
- data/lib/sy/quantity.rb +7 -46
- data/lib/sy/signed_magnitude.rb +3 -15
- data/lib/sy/unit.rb +3 -17
- data/lib/sy/version.rb +1 -3
- data/test/sy_test.rb +45 -63
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05a4502f974a88c613b402394d0e303bac458836
|
4
|
+
data.tar.gz: 799053c77aef863d27d6d5e816289a26fe48952d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d83e13e2eac8a780dce7ea70f9f578586bbf749e9d1aec39345b9a6d5f0b4dc24754ce0cfd81671cddef6016cc6a242a1885e3b0be09f827cd410139c6a6d8d
|
7
|
+
data.tar.gz: 90f1266a32befff128873f820ebc679ff97de0a5f3325724864f3b24b7e4c9d32b8b50d362a256419a886f5ab61f9ac8bf0af087d2915422b6f5aa9b956e6bb5
|
data/lib/sy.rb
CHANGED
@@ -5,7 +5,6 @@ require 'y_support/name_magic'
|
|
5
5
|
require 'y_support/core_ext/hash'
|
6
6
|
require 'y_support/typing'
|
7
7
|
require 'y_support/unicode'
|
8
|
-
require 'y_support/abstract_algebra'
|
9
8
|
|
10
9
|
require 'active_support/core_ext/module/delegation'
|
11
10
|
require 'active_support/core_ext/array/extract_options'
|
@@ -71,10 +70,7 @@ module SY
|
|
71
70
|
# of the constant "UNIT" implies, via YSupport's NameMagic mixin, that the
|
72
71
|
# name of the object becomes :unit and that it is possible to use syntax
|
73
72
|
# such as 42.unit to create magnitudes of SY::Amount.
|
74
|
-
puts "About to construct UNIT." if SY::DEBUG
|
75
73
|
UNIT = Unit.standard of: Amount
|
76
|
-
puts "UNIT constructed. SY::Unit instances are " +
|
77
|
-
"#{SY::Unit.instance_names}" if SY::DEBUG
|
78
74
|
|
79
75
|
# AVOGADRO_CONSTANT (Nᴀ) is a certain well-known amount of things:
|
80
76
|
Nᴀ = AVOGADRO_CONSTANT = 6.02214e23
|
@@ -83,11 +79,7 @@ module SY
|
|
83
79
|
MoleAmount = Quantity.dimensionless coerces: Amount
|
84
80
|
|
85
81
|
# And let SY::MOLE be its standard unit, related to SY::Amount via Nᴀ:
|
86
|
-
puts "About to construct MOLE." if SY::DEBUG
|
87
82
|
MOLE = Unit.standard of: MoleAmount, short: "mol", amount: Nᴀ * UNIT
|
88
|
-
puts SY::Unit.__instances__ if SY::DEBUG
|
89
|
-
puts "MOLE constructed. SY::Unit instances are" +
|
90
|
-
"#{SY::Unit.instance_names}" if SY::DEBUG
|
91
83
|
|
92
84
|
# === Basic dimension L (length)
|
93
85
|
|
@@ -185,7 +177,7 @@ module SY
|
|
185
177
|
super
|
186
178
|
end
|
187
179
|
|
188
|
-
#
|
180
|
+
# TODO: #% method etc
|
189
181
|
end
|
190
182
|
|
191
183
|
# Making sure that for Celsius temperature, #°C returns absolute magnitude.
|
@@ -196,10 +188,6 @@ module SY
|
|
196
188
|
end
|
197
189
|
end
|
198
190
|
|
199
|
-
# FIXME: Make this more systematic.
|
200
|
-
# FIXME: Make sure that SI prefixes may not be used with Celsius
|
201
|
-
# FIXME: Make sure that highly unusual SI prefixes may not be used
|
202
|
-
|
203
191
|
class << CelsiusTemperature.send( :Magnitude )
|
204
192
|
include SY::CelsiusMagnitude
|
205
193
|
end
|
@@ -208,32 +196,9 @@ module SY
|
|
208
196
|
include SY::CelsiusMagnitude
|
209
197
|
end
|
210
198
|
|
211
|
-
# alias :°C :celsius # with U+00B0 DEGREE SIGN
|
212
|
-
# alias :˚C :celsius # with U+02DA RING ABOVE
|
213
|
-
# alias :℃ :celsius # U+2103 DEGREE CELSIUS
|
214
|
-
|
215
|
-
# FahrenheitTemperature = Quantity.of :Θ
|
216
|
-
# FAHRENHEIT = Unit.standard of: FahrenheitTemperature, short: '°F'
|
217
|
-
# # alias :°F :fahrenheit # with U+00B0 DEGREE SIGN
|
218
|
-
# # alias :˚F :fahrenheit # with U+02DA RING ABOVE
|
219
|
-
# # alias :℉ :fahrenheit # U+2109 DEGREE FAHRENHEIT
|
220
|
-
# # FIXME: Patch FahrenheitTemperature to make it work with SY::Temperature
|
221
|
-
|
222
|
-
|
223
|
-
# HUMAN_BODY_TEMPERATURE = 37.°C.( KELVIN )
|
224
|
-
# STANDARD_TEMPERATURE = 25.°C.( KELVIN )
|
225
199
|
HUMAN_BODY_TEMPERATURE = TP_H₂O + 37 * KELVIN
|
226
200
|
STANDARD_LABORATORY_TEMPERATURE = TP_H₂O + 25 * KELVIN
|
227
201
|
|
228
|
-
# === Dimensionless quantities
|
229
|
-
|
230
|
-
# For now, these are just unimplemented proposals of what users might expect
|
231
|
-
# from SY:
|
232
|
-
#
|
233
|
-
# degree, alias deg, ° # angle measure
|
234
|
-
# arcminute, alias ʹ, ′ # angle measure
|
235
|
-
# arcsecond, alias ʹʹ, ′′, ″
|
236
|
-
|
237
202
|
# === Quantities of composite dimensions
|
238
203
|
|
239
204
|
# Quantity SY::Area is obtained by raising quantity SY::Length to 2:
|
@@ -281,7 +246,7 @@ module SY
|
|
281
246
|
# of its dimension.
|
282
247
|
Speed = ( Length / Time ).standard!
|
283
248
|
|
284
|
-
#
|
249
|
+
# Commonly used constant.
|
285
250
|
SPEED_OF_LIGHT = 299_792_458 * METRE / SECOND
|
286
251
|
|
287
252
|
# Supplementary unit of length.
|
@@ -299,7 +264,7 @@ module SY
|
|
299
264
|
# For SY::Energy...
|
300
265
|
Energy = ( Force * Length ).standard!
|
301
266
|
|
302
|
-
#
|
267
|
+
# Make SY::JOULE its standard unit:
|
303
268
|
JOULE = Unit.standard of: Energy, short: "J"
|
304
269
|
# SY::CALORIE means thermochemical calorie:
|
305
270
|
CALORIE = Unit.of Energy, short: "cal", amount: 4.184 * JOULE
|
@@ -331,11 +296,6 @@ module SY
|
|
331
296
|
# make SY::VOLT its standard unit:
|
332
297
|
VOLT = Unit.standard of: ElectricPotential, short: "V"
|
333
298
|
|
334
|
-
# TODO: This should raise a friendly error:
|
335
|
-
# MOLAR = Unit.standard of: Molarity, short: "M", amount: 1.mol.l⁻¹
|
336
|
-
# (normal way of definition is MOLAR = Unit.standard of: Molarity, short: "M"
|
337
|
-
# and it has already been defined to boot)
|
338
|
-
|
339
299
|
# SY::Molality...
|
340
300
|
Molality = MoleAmount / Mass
|
341
301
|
|
@@ -351,4 +311,4 @@ module SY
|
|
351
311
|
ELEMENTARY_CHARGE = 1.60217656535e-19 * COULOMB
|
352
312
|
|
353
313
|
ELECTRONVOLT = Unit.of Energy, short: "eV", amount: ELEMENTARY_CHARGE * VOLT
|
354
|
-
end
|
314
|
+
end
|
@@ -18,24 +18,15 @@ module SY::AbsoluteMagnitude
|
|
18
18
|
# and :amount named argument, where amount must be nonnegative.
|
19
19
|
#
|
20
20
|
def initialize( of: nil, amount: nil )
|
21
|
-
puts "Constructing AbsoluteMagnitude of #{of}, amount: #{amount}" if SY::DEBUG
|
22
21
|
fail ArgumentError, "Quantity (:of) argument missing!" if of.nil?
|
23
22
|
@quantity = of
|
24
23
|
@amount = case amount
|
25
|
-
when Numeric then
|
26
|
-
|
27
|
-
amount
|
28
|
-
when nil then
|
29
|
-
puts "This amount is 'nil', using 1 instead" if SY::DEBUG
|
30
|
-
1
|
24
|
+
when Numeric then amount
|
25
|
+
when nil then 1
|
31
26
|
else
|
32
27
|
begin
|
33
|
-
puts "Amount #{amount} will be reframed to #{@quantity}" if SY::DEBUG
|
34
28
|
amount.( @quantity ).amount
|
35
|
-
rescue NameError, NoMethodError
|
36
|
-
puts "fail, amount #{amount} will be used directly" if SY::DEBUG
|
37
|
-
amount
|
38
|
-
end
|
29
|
+
rescue NameError, NoMethodError; amount end
|
39
30
|
end
|
40
31
|
fail SY::MagnitudeError, "Attempt to construct an unsigned magnitude " +
|
41
32
|
"(SY::AbsoluteMagnitude) with a negative amount." if @amount < 0
|
@@ -44,16 +35,12 @@ module SY::AbsoluteMagnitude
|
|
44
35
|
# For absolute magnitudes, #+ method always returns a result framed in
|
45
36
|
# corresponding relative quantity.
|
46
37
|
#
|
47
|
-
# TODO: Figure out which module comes on the top in Quantity@Magnitude, whether Magnitude
|
48
|
-
# or SignedMagnitude, and therefore, whether it is necessary to adjust this method.
|
49
38
|
def + m2
|
50
39
|
return magnitude amount + m2.amount if m2.quantity == quantity.relative
|
51
40
|
return quantity.relative.magnitude( amount + m2.amount ) if
|
52
41
|
quantity == m2.quantity
|
53
42
|
return self if m2.equal? SY::ZERO
|
54
|
-
|
55
|
-
# return o1 + o2
|
56
|
-
raise SY::QuantityError, "Unable to perform #{quantity} + #{m2.quantity}!"
|
43
|
+
fail SY::QuantityError, "Unable to perform #{quantity} + #{m2.quantity}!"
|
57
44
|
end
|
58
45
|
|
59
46
|
# Addition of absolute magnitudes that returns a result framed as
|
@@ -62,24 +49,18 @@ module SY::AbsoluteMagnitude
|
|
62
49
|
def add m2
|
63
50
|
return magnitude( amount + m2.amount ) if quantity == m2.quantity
|
64
51
|
return self if m2.equal? SY::ZERO
|
65
|
-
|
66
|
-
# return o1.add o2
|
67
|
-
raise SY::QuantityError, "Unable to perform #add with #{m2.quantity}!"
|
52
|
+
fail SY::QuantityError, "Unable to perform #add with #{m2.quantity}!"
|
68
53
|
end
|
69
54
|
|
70
55
|
# For absolute magnitudes, #- method always returns a result framed in
|
71
56
|
# corresponding relative quantity.
|
72
57
|
#
|
73
|
-
# TODO: Figure out which module comes on the top in Quantity@Magnitude, whether Magnitude
|
74
|
-
# or SignedMagnitude, and therefore, whether it is necessary to adjust this method.
|
75
58
|
def - m2
|
76
59
|
return magnitude amount - m2.amount if m2.quantity == quantity.relative
|
77
60
|
return quantity.relative.magnitude( amount - m2.amount ) if
|
78
61
|
quantity == m2.quantity
|
79
62
|
return self if m2.equal? SY::ZERO
|
80
|
-
|
81
|
-
# return o1 - o2
|
82
|
-
raise( SY::QuantityError, "Unable to perform #{quantity} - #{m2.quantity}!" )
|
63
|
+
fail SY::QuantityError, "Unable to perform #{quantity} - #{m2.quantity}!"
|
83
64
|
end
|
84
65
|
|
85
66
|
# Subtraction of absolute magnitudes that returns a result framed as
|
@@ -89,9 +70,7 @@ module SY::AbsoluteMagnitude
|
|
89
70
|
def subtract m2
|
90
71
|
return magnitude( amount + m2.amount ) if quantity == m2.quantity
|
91
72
|
return self if m2.equal? SY::ZERO
|
92
|
-
|
93
|
-
# return o1.subtract o2
|
94
|
-
raise( SY::QuantityError, "Unable to perform #add with #{m2.quantity}!" )
|
73
|
+
fail SY::QuantityError, "Unable to perform #add with #{m2.quantity}!"
|
95
74
|
end
|
96
75
|
|
97
76
|
# "Subtraction" of absolute magnitudes, that never takes more thant the
|
@@ -112,7 +91,5 @@ module SY::AbsoluteMagnitude
|
|
112
91
|
|
113
92
|
# String describing this class.
|
114
93
|
#
|
115
|
-
def
|
116
|
-
"Magnitude"
|
117
|
-
end
|
94
|
+
def çς; "Magnitude" end
|
118
95
|
end # class SY::AbsoluteMagnitude
|
data/lib/sy/composition.rb
CHANGED
@@ -28,8 +28,8 @@ class SY::Composition < Hash
|
|
28
28
|
ꜧ.reject! { |_, exp| exp == 0 }
|
29
29
|
}
|
30
30
|
|
31
|
-
#
|
32
|
-
#
|
31
|
+
# This simplification rule simplifies MoleAmount and LitreVolume into
|
32
|
+
# Molarity.
|
33
33
|
#
|
34
34
|
SR << -> ꜧ {
|
35
35
|
begin
|
@@ -61,8 +61,8 @@ class SY::Composition < Hash
|
|
61
61
|
return ꜧ
|
62
62
|
}
|
63
63
|
|
64
|
-
#
|
65
|
-
#
|
64
|
+
# This simplification rule simplifies LitreVolume times Molarity into
|
65
|
+
# MoleAmount.
|
66
66
|
#
|
67
67
|
SR << -> ꜧ {
|
68
68
|
begin
|
@@ -130,8 +130,6 @@ class SY::Composition < Hash
|
|
130
130
|
# is a base dimension.
|
131
131
|
#
|
132
132
|
def atomic?
|
133
|
-
puts "composition is #{self}" if SY::DEBUG
|
134
|
-
puts "first[0].dimension is #{first[0].dimension}" if SY::DEBUG
|
135
133
|
singular? && first[0].dimension.base?
|
136
134
|
end
|
137
135
|
|
@@ -206,9 +204,8 @@ class SY::Composition < Hash
|
|
206
204
|
#
|
207
205
|
def simplify
|
208
206
|
ꜧ = self.to_hash
|
209
|
-
puts "simplifying #{ꜧ}" if SY::DEBUG
|
210
207
|
SIMPLIFICATION_RULES.each { |rule| rule.( ꜧ ) }
|
211
|
-
self.class[ ꜧ ]
|
208
|
+
self.class[ ꜧ ]
|
212
209
|
end
|
213
210
|
|
214
211
|
# Returns the quantity appropriate to this composition.
|
@@ -236,15 +233,8 @@ class SY::Composition < Hash
|
|
236
233
|
# of the pertinent standard quantity.)
|
237
234
|
#
|
238
235
|
def infer_measure
|
239
|
-
puts "#infer_measure; hash is #{self}" if SY::DEBUG
|
240
236
|
map do |qnt, exp|
|
241
|
-
|
242
|
-
if qnt.standardish? then
|
243
|
-
puts "#{qnt} standardish" if SY::DEBUG
|
244
|
-
SY::Measure.identity
|
245
|
-
else
|
246
|
-
puts "#{qnt} not standardish" if SY::DEBUG
|
247
|
-
puts "its measure is #{qnt.measure}, class #{qnt.measure.class}" if SY::DEBUG
|
237
|
+
if qnt.standardish? then SY::Measure.identity else
|
248
238
|
qnt.measure( of: qnt.standard ) ** exp
|
249
239
|
end
|
250
240
|
end.reduce( SY::Measure.identity, :* )
|
@@ -265,18 +255,13 @@ class SY::Composition < Hash
|
|
265
255
|
#
|
266
256
|
def expand
|
267
257
|
return self if irreducible?
|
268
|
-
puts "#expand: #{self} not irreducible" if SY::DEBUG
|
269
258
|
self.class[ reduce( self.class.empty ) { |cᴍ, pair|
|
270
259
|
qnt, exp = pair
|
271
|
-
puts "#expand: qnt: #{qnt}, exp: #{exp}" if SY::DEBUG
|
272
|
-
puts "cᴍ is #{cᴍ}" if SY::DEBUG
|
273
260
|
( cᴍ + if qnt.irreducible? then
|
274
261
|
self.class.singular( qnt ) * exp
|
275
262
|
else
|
276
263
|
qnt.composition * exp
|
277
|
-
end
|
278
|
-
).tap { |x| puts "Result is #{x}." if SY::DEBUG }
|
264
|
+
end )
|
279
265
|
} ]
|
280
|
-
.tap{ |rslt| puts "#expand: result is #{rslt}" if SY::DEBUG }
|
281
266
|
end
|
282
267
|
end # class SY::Composition
|
data/lib/sy/dimension.rb
CHANGED
@@ -39,9 +39,7 @@ class SY::Dimension
|
|
39
39
|
|
40
40
|
# Presents class-owned instances (array).
|
41
41
|
#
|
42
|
-
def instances
|
43
|
-
return @instances ||= []
|
44
|
-
end
|
42
|
+
def instances; return @instances ||= [] end
|
45
43
|
|
46
44
|
# Base dimension constructor. Base dimension symbol is expeced as argument.
|
47
45
|
#
|
@@ -23,7 +23,7 @@ module SY::ExpressibleInUnits
|
|
23
23
|
im = instance_method ß
|
24
24
|
warn w unless ::SY::ExpressibleInUnits.method_family.include? im if
|
25
25
|
ꜧ[ß].warns? unless instance_variable_get( :@no_collision ) == ß
|
26
|
-
instance_variable_set( :@no_collision, nil )
|
26
|
+
instance_variable_set( :@no_collision, nil )
|
27
27
|
else
|
28
28
|
warn w if ꜧ[ß].warns?
|
29
29
|
end
|
@@ -33,7 +33,7 @@ module SY::ExpressibleInUnits
|
|
33
33
|
im = instance_method ß
|
34
34
|
warn w unless ::SY::ExpressibleInUnits.method_family.include? im if
|
35
35
|
ꜧ[ß].warns? unless instance_variable_get( :@no_collision ) == ß
|
36
|
-
instance_variable_set( :@no_collision, nil )
|
36
|
+
instance_variable_set( :@no_collision, nil )
|
37
37
|
else
|
38
38
|
warn w if ꜧ[ß].warns?
|
39
39
|
end
|
@@ -83,10 +83,7 @@ module SY::ExpressibleInUnits
|
|
83
83
|
def known_units
|
84
84
|
begin
|
85
85
|
unit_namespace.instances
|
86
|
-
rescue NoMethodError
|
87
|
-
[] # no #instances method defined yet
|
88
|
-
end
|
89
|
-
.tap { |r| puts "Known units are #{r}" if SY::DEBUG }
|
86
|
+
rescue NoMethodError; [] end
|
90
87
|
end
|
91
88
|
|
92
89
|
# All methods defined by this mixin.
|
@@ -98,7 +95,6 @@ module SY::ExpressibleInUnits
|
|
98
95
|
# Find unit based on name / abbreviation.
|
99
96
|
#
|
100
97
|
def find_unit ς
|
101
|
-
puts "searching for unit #{ς}" if SY::DEBUG
|
102
98
|
known_units.find do |u|
|
103
99
|
u.name.to_s.downcase == ς.downcase &&
|
104
100
|
( ς == ς.downcase || ς == ς.upcase ) ||
|
@@ -109,7 +105,6 @@ module SY::ExpressibleInUnits
|
|
109
105
|
# Return prefix method or empty string, if prefix method not necessary.
|
110
106
|
#
|
111
107
|
def prefix_method_string prefix
|
112
|
-
puts "About to call PREFIX TABLE.to_full with #{prefix}" if SY::DEBUG
|
113
108
|
full_prefix = SY::PREFIX_TABLE.to_full( prefix )
|
114
109
|
full_prefix == '' ? '' : ".#{full_prefix}"
|
115
110
|
end
|
@@ -126,19 +121,12 @@ module SY::ExpressibleInUnits
|
|
126
121
|
super if ß.to_s =~ /to_.+/ # dissmiss :to_..., esp. :to_ary
|
127
122
|
begin # prevent recurrent call of method_missing for the same symbol
|
128
123
|
anti_recursion_exec token: ß, var: :@SY_Units_mmiss do
|
129
|
-
puts "Method missing: '#{ß}'" if SY::DEBUG
|
130
124
|
prefixes, units, exps = parse_unit_symbol ß
|
131
|
-
|
132
|
-
# I'D HAVE TO PERFORM THE COLLISION CHECK HERE
|
133
|
-
# IF NO COLLISION, INFORM THE SUBSEQUENT METHOD DEFINED CALL ON
|
134
|
-
# SELF.CLASS
|
135
|
-
puts "parsed" if SY::DEBUG
|
136
|
-
self.class.instance_variable_set "@no_collision", ß # FIXME: This is too clumsy
|
125
|
+
self.class.instance_variable_set "@no_collision", ß
|
137
126
|
self.class.module_eval write_unit_method( ß, prefixes, units, exps )
|
138
127
|
SY::ExpressibleInUnits.method_family << self.class.instance_method( ß )
|
139
128
|
end
|
140
129
|
rescue NameError => err
|
141
|
-
puts "NameError raised: #{err}" if SY::DEBUG
|
142
130
|
super # give up
|
143
131
|
rescue SY::ExpressibleInUnits::RecursionError
|
144
132
|
super # give up
|
@@ -167,7 +155,6 @@ module SY::ExpressibleInUnits
|
|
167
155
|
# figures out which SY units it represents, along with prefixes and exponents.
|
168
156
|
#
|
169
157
|
def parse_unit_symbol ß
|
170
|
-
puts "About to parse #{ß} using all prefixes" if SY::DEBUG
|
171
158
|
SY::Unit.parse_sps_using_all_prefixes( ß ) # rely on SY::Unit
|
172
159
|
end
|
173
160
|
|
@@ -176,12 +163,10 @@ module SY::ExpressibleInUnits
|
|
176
163
|
# Arrays must be of equal length. (Note: 'ß' is 'symbol', 'ς' is 'string')
|
177
164
|
#
|
178
165
|
def write_unit_method ß, prefixes, units, exponents
|
179
|
-
puts "writing unit method #{ß}" if SY::DEBUG
|
180
166
|
# Prepare prefix / unit / exponent triples for making factor strings:
|
181
167
|
triples = [ prefixes, units, exponents ].transpose
|
182
168
|
# A procedure for triple processing before use:
|
183
169
|
process_triple = lambda do |pfx, unit_ς, exp|
|
184
|
-
puts "Processing triple #{pfx}, #{unit_ς}, #{exp}." if SY::DEBUG
|
185
170
|
[ ::SY::ExpressibleInUnits.find_unit( unit_ς ).name.to_s.upcase,
|
186
171
|
::SY::ExpressibleInUnits.prefix_method_string( pfx ),
|
187
172
|
::SY::ExpressibleInUnits.exponentiation_string( exp ) ]
|
@@ -211,7 +196,7 @@ module SY::ExpressibleInUnits
|
|
211
196
|
method_body = factors.join( " * \n " )
|
212
197
|
end
|
213
198
|
# Return the finished method string:
|
214
|
-
return ( method_skeleton % method_body )
|
199
|
+
return ( method_skeleton % method_body )
|
215
200
|
end
|
216
201
|
|
217
202
|
# Takes a token as the first argument, a symbol of the instance variable to
|
@@ -230,9 +215,4 @@ module SY::ExpressibleInUnits
|
|
230
215
|
registry.delete token
|
231
216
|
end
|
232
217
|
end
|
233
|
-
|
234
|
-
# FIXME: There should be an option to define by default, already at the
|
235
|
-
# beginning, certain methods for certain classes, to get in front of possible
|
236
|
-
# collisions. Collision was detected for example for #second with
|
237
|
-
# active_support/duration.rb
|
238
218
|
end
|
@@ -18,22 +18,16 @@ module SY
|
|
18
18
|
class << BASE_DIMENSIONS
|
19
19
|
# Letters of the base dimensions.
|
20
20
|
#
|
21
|
-
def letters
|
22
|
-
keys
|
23
|
-
end
|
21
|
+
def letters; keys end
|
24
22
|
|
25
23
|
# Base dimensions letters with prefixes. (Remark: I forgot what did I mean
|
26
24
|
# those prefixes for. Something important, I just forgot what.)
|
27
25
|
#
|
28
|
-
def prefixed_letters
|
29
|
-
[] # none for now
|
30
|
-
end
|
26
|
+
def prefixed_letters; [] end
|
31
27
|
|
32
28
|
# Base dimension symbols – letters and prefixed letters.
|
33
29
|
#
|
34
|
-
def base_symbols
|
35
|
-
@baseß ||= letters + prefixed_letters
|
36
|
-
end
|
30
|
+
def base_symbols; @baseß ||= letters + prefixed_letters end
|
37
31
|
alias basic_symbols base_symbols
|
38
32
|
|
39
33
|
# Takes an sps representing a dimension, and converts it to a hash of
|
@@ -45,7 +39,7 @@ module SY
|
|
45
39
|
end
|
46
40
|
end
|
47
41
|
|
48
|
-
|
42
|
+
# Table of standard prefixes and their corresponding unit multiples.
|
49
43
|
#
|
50
44
|
PREFIX_TABLE = [ { full: "exa", short: "E", factor: 1e18 },
|
51
45
|
{ full: "peta", short: "P", factor: 1e15 },
|
@@ -144,9 +138,7 @@ module SY
|
|
144
138
|
SUPERSCRIPT = Hash.new { |ꜧ, key|
|
145
139
|
if key.is_a? String then
|
146
140
|
key.size <= 1 ? nil : key.each_char.map{|c| ꜧ[c] }.join
|
147
|
-
else
|
148
|
-
ꜧ[key.to_s]
|
149
|
-
end
|
141
|
+
else ꜧ[key.to_s] end
|
150
142
|
}.merge! Hash[ '-/0123456789'.each_char.zip( '⁻⎖⁰¹²³⁴⁵⁶⁷⁸⁹'.each_char ) ]
|
151
143
|
|
152
144
|
# Reverse conversion of Unicode superscript exponents (from exponent
|
@@ -155,9 +147,7 @@ module SY
|
|
155
147
|
SUPERSCRIPT_DOWN = Hash.new { |ꜧ, key|
|
156
148
|
if key.is_a? String then
|
157
149
|
key.size == 1 ? nil : key.each_char.map{|c| ꜧ[c] }.join
|
158
|
-
else
|
159
|
-
ꜧ[key.to_s]
|
160
|
-
end
|
150
|
+
else ꜧ[key.to_s] end
|
161
151
|
}.merge!( SUPERSCRIPT.invert ).merge!( '¯' => '-', # other superscript chars
|
162
152
|
'´' => '/' )
|
163
153
|
|
data/lib/sy/magnitude.rb
CHANGED
@@ -265,124 +265,16 @@ module SY::Magnitude
|
|
265
265
|
|
266
266
|
#
|
267
267
|
def to_s( unit=quantity.units.first || quantity.standard_unit,
|
268
|
-
number_format=default_amount_format )
|
269
|
-
puts "#to_s called on a magnitude of quantity #{quantity}" if SY::DEBUG
|
270
|
-
# step 1: produce pairs [number, unit_presentation],
|
271
|
-
# where unit_presentation is an array of triples
|
272
|
-
# [prefix, unit, exponent], which together give the
|
273
|
-
# correct dimension for this magnitude, and correct
|
274
|
-
# factor so that number * factor == self.amount
|
275
|
-
# step 2: define a goodness function for them
|
276
|
-
# step 3: define a satisfaction criterion
|
277
|
-
# step 4: maximize this goodness function until the satisfaction
|
278
|
-
# criterion is met
|
279
|
-
# step 5: interpolate the string from the chosen choice
|
280
|
-
|
281
|
-
# so, let's start doing it
|
282
|
-
# how do we produce the first choice?
|
283
|
-
# if the standard unit for this quantity is named, we'll start with it
|
284
|
-
|
285
|
-
# let's say that the abbreviation of this std. unit is Uu, so the first
|
286
|
-
# choices will be:
|
287
|
-
#
|
288
|
-
# amount.Uu
|
289
|
-
# (amount * 1000).µUu
|
290
|
-
# (amount / 1000).kUu
|
291
|
-
# (amount * 1_000_000).nUu
|
292
|
-
# (amount / 1_000_000).MUu
|
293
|
-
# ...
|
294
|
-
#
|
295
|
-
# (let's say we'll use only short prefixes)
|
296
|
-
#
|
297
|
-
# which one do we use?
|
298
|
-
# That depends. For example, CelsiusTemperature is never rendered with
|
299
|
-
# SI prefixes, so their cost should be +Infinity
|
300
|
-
#
|
301
|
-
# Cost of the number could be eg.:
|
302
|
-
#
|
303
|
-
# style: cost:
|
304
|
-
# 3.141 0
|
305
|
-
# 31.41, 314.1 1
|
306
|
-
# 0.3141 2
|
307
|
-
# 3141.0 3
|
308
|
-
# 0.03141 4
|
309
|
-
# 31410.0 5n
|
310
|
-
# 0.003141 6
|
311
|
-
# ...
|
312
|
-
#
|
313
|
-
# Default cost of prefixes could be eg.
|
314
|
-
#
|
315
|
-
# unit representation: cost:
|
316
|
-
# U 0
|
317
|
-
# dU +Infinity
|
318
|
-
# cU +Infinity
|
319
|
-
# mU 1
|
320
|
-
# dkU +Infinity
|
321
|
-
# hU +Infinity
|
322
|
-
# kU 1
|
323
|
-
# µU 2
|
324
|
-
# MU 2
|
325
|
-
# nU 3
|
326
|
-
# GU 3
|
327
|
-
# pU 4
|
328
|
-
# TU 4
|
329
|
-
# fU 5
|
330
|
-
# PU 5
|
331
|
-
# aU 6
|
332
|
-
# EU 6
|
333
|
-
#
|
334
|
-
# Cost of exponents could be eg. their absolute value, and +1 for minus sign
|
335
|
-
#
|
336
|
-
# Same unit with two different prefixes may never be used (cost +Infinity)
|
337
|
-
#
|
338
|
-
# Afterwards, there should be cost of inconsistency. This could be implemented
|
339
|
-
# eg. as computing the first 10 possibilities for amount: 1 and giving them
|
340
|
-
# bonuses -20, -15, -11, -8, -6, -5, -4, -3, -2, -1. That would further reduce the variability of the
|
341
|
-
# unit representations.
|
342
|
-
#
|
343
|
-
# Commenting again upon default cost of prefixes, prefixes before second:
|
344
|
-
#
|
345
|
-
# prefix: cost:
|
346
|
-
# s 0
|
347
|
-
# ms 4
|
348
|
-
# ns 5
|
349
|
-
# ps 6
|
350
|
-
# fs 7
|
351
|
-
# as 9
|
352
|
-
# ks +Infinity
|
353
|
-
# Ms +Infinity
|
354
|
-
# ...
|
355
|
-
#
|
356
|
-
# Prefixes before metre
|
357
|
-
#
|
358
|
-
# prefix: cost:
|
359
|
-
# m 0
|
360
|
-
# mm 2
|
361
|
-
# µm 2
|
362
|
-
# nm 3
|
363
|
-
# km 3
|
364
|
-
# Mm +Infinity
|
365
|
-
# ...
|
366
|
-
#
|
367
|
-
|
368
|
-
# number, unit_presentation = choice
|
369
|
-
|
370
|
-
# return "#{amount} of #{quantity}"
|
371
|
-
|
268
|
+
number_format=default_amount_format )
|
372
269
|
begin
|
373
|
-
|
374
270
|
un = unit.short || unit.name
|
375
|
-
|
376
271
|
if un then
|
377
272
|
number = self.in unit
|
378
273
|
number_ς = number_format % number
|
379
|
-
|
380
274
|
prefix = ''
|
381
275
|
exp = 1
|
382
276
|
# unit_presentation = prefix, unit, exp
|
383
|
-
|
384
277
|
unit_ς = SY::SPS.( [ "#{prefix}#{unit.short}" ], [ exp ] )
|
385
|
-
|
386
278
|
[ number_ς, unit_ς ].join '.'
|
387
279
|
else
|
388
280
|
number = amount
|
@@ -406,7 +298,6 @@ module SY::Magnitude
|
|
406
298
|
return number_ς if unit_ς == '' || unit_ς == 'unit'
|
407
299
|
[ number_ς, unit_ς ].join '.'
|
408
300
|
end
|
409
|
-
|
410
301
|
rescue
|
411
302
|
fail
|
412
303
|
number_ς = number_format % amount
|
@@ -414,29 +305,9 @@ module SY::Magnitude
|
|
414
305
|
end
|
415
306
|
end
|
416
307
|
|
417
|
-
# def to_s unit=quantity.units.first, number_format='%.3g'
|
418
|
-
# begin
|
419
|
-
# return to_string( unit ) if unit and unit.abbreviation
|
420
|
-
# rescue
|
421
|
-
# end
|
422
|
-
# # otherwise, use units of basic dimensions – here be the magic:
|
423
|
-
# hsh = dimension.to_hash
|
424
|
-
# symbols, exponents = hsh.each_with_object Hash.new do |pair, memo|
|
425
|
-
# dimension_letter, exponent = pair
|
426
|
-
# std_unit = SY::Dimension.basic( dimension_letter ).standard_unit
|
427
|
-
# memo[ std_unit.abbreviation || std_unit.name ] = exponent
|
428
|
-
# end.to_a.transpose
|
429
|
-
# # assemble the superscripted product string:
|
430
|
-
# sps = SY::SPS.( symbols, exponents )
|
431
|
-
# # and finally, interpolate the string
|
432
|
-
# "#{number_format}#{sps == '' ? '' : '.' + sps}" % amount
|
433
|
-
# "#{amount}#{sps == '' ? '' : '.' + sps}"
|
434
|
-
# end
|
435
|
-
|
436
308
|
# Inspect string of the magnitude
|
437
309
|
#
|
438
310
|
def inspect
|
439
|
-
puts "inspect called on a magnitude of quantity #{quantity}" if SY::DEBUG
|
440
311
|
"#<#{çς}: #{self} >"
|
441
312
|
end
|
442
313
|
|
data/lib/sy/mapping.rb
CHANGED
@@ -12,15 +12,11 @@ class SY::Measure
|
|
12
12
|
class << self
|
13
13
|
# Identity measure.
|
14
14
|
#
|
15
|
-
def identity
|
16
|
-
simple_scale 1
|
17
|
-
end
|
15
|
+
def identity; simple_scale 1 end
|
18
16
|
|
19
17
|
# Simple scaling measure. (Eg. pounds vs kilograms)
|
20
18
|
#
|
21
|
-
def simple_scale scale
|
22
|
-
new( ratio: scale )
|
23
|
-
end
|
19
|
+
def simple_scale scale; new( ratio: scale ) end
|
24
20
|
|
25
21
|
# Simple offset measure. (Such as °C)
|
26
22
|
#
|
@@ -89,11 +85,8 @@ class SY::Measure
|
|
89
85
|
# Inverse measure.
|
90
86
|
#
|
91
87
|
def inverse
|
92
|
-
if ratio.nil? then
|
93
|
-
|
94
|
-
else
|
95
|
-
self.class.new( ratio: 1 / ratio )
|
96
|
-
end
|
88
|
+
if ratio.nil? then self.class.new( r: w, w: r ) # swap closures
|
89
|
+
else self.class.new( ratio: 1 / ratio ) end
|
97
90
|
end
|
98
91
|
|
99
92
|
# Measure composition (like f * g function composition).
|
data/lib/sy/matrix.rb
CHANGED
@@ -65,9 +65,7 @@ class Matrix
|
|
65
65
|
def /(other)
|
66
66
|
case other
|
67
67
|
when Numeric
|
68
|
-
rows = @rows.collect
|
69
|
-
row.collect {|e| e / other }
|
70
|
-
}
|
68
|
+
rows = @rows.collect do |row| row.collect {|e| e / other } end
|
71
69
|
return new_matrix rows, column_count
|
72
70
|
when Matrix
|
73
71
|
return self * other.inverse
|
data/lib/sy/measure.rb
CHANGED
@@ -87,11 +87,8 @@ class SY::Measure
|
|
87
87
|
# Inverse measure.
|
88
88
|
#
|
89
89
|
def inverse
|
90
|
-
if ratio.nil? then
|
91
|
-
|
92
|
-
else
|
93
|
-
self.class.new( ratio: 1 / ratio )
|
94
|
-
end
|
90
|
+
if ratio.nil? then self.class.new( r: w, w: r ) # swap closures
|
91
|
+
else self.class.new( ratio: 1 / ratio ) end
|
95
92
|
end
|
96
93
|
|
97
94
|
# Measure composition (like f * g function composition).
|
@@ -101,9 +98,7 @@ class SY::Measure
|
|
101
98
|
r1, r2, w1, w2 = r, other.r, w, other.w
|
102
99
|
self.class.new( r: lambda { |ref_amnt| r1.( r2.( ref_amnt ) ) },
|
103
100
|
w: lambda { |amnt| w2.( w1.( amnt ) ) } )
|
104
|
-
else
|
105
|
-
self.class.new( ratio: ratio * other.ratio )
|
106
|
-
end
|
101
|
+
else self.class.new( ratio: ratio * other.ratio ) end
|
107
102
|
end
|
108
103
|
|
109
104
|
# Measure composition with inverse of another measure.
|
data/lib/sy/quantity.rb
CHANGED
@@ -5,10 +5,6 @@
|
|
5
5
|
class SY::Quantity
|
6
6
|
include NameMagic
|
7
7
|
|
8
|
-
# name_set_hook do |name, new_instance, old_name|
|
9
|
-
# new_instance.protect!; name
|
10
|
-
# end
|
11
|
-
|
12
8
|
RELATIVE_QUANTITY_NAME_SUFFIX = "±"
|
13
9
|
|
14
10
|
attr_reader :MagnitudeModule, :Magnitude, :Unit
|
@@ -38,7 +34,6 @@ class SY::Quantity
|
|
38
34
|
#
|
39
35
|
def standard( of: nil )
|
40
36
|
fail ArgumentError, "Dimension (:of argument) must be given!" if of.nil?
|
41
|
-
puts "Constructing standard quantity of #{of} dimension" if SY::DEBUG
|
42
37
|
return SY.Dimension( of ).standard_quantity
|
43
38
|
end
|
44
39
|
|
@@ -64,14 +59,11 @@ class SY::Quantity
|
|
64
59
|
coerces: [],
|
65
60
|
coerces_to: [],
|
66
61
|
**nn )
|
67
|
-
puts "Quantity init relative: #{relative}, composition: #{composition}, measure: #{measure}, #{nn}" if SY::DEBUG
|
68
62
|
@units = [] # array of units as favored by this quantity
|
69
63
|
@relative = relative
|
70
64
|
if composition.nil? then
|
71
|
-
puts "Composition not given, dimension expected." if SY::DEBUG
|
72
65
|
@dimension = SY.Dimension( of )
|
73
66
|
else
|
74
|
-
puts "Composition received (#{composition})." if SY::DEBUG
|
75
67
|
@composition = SY::Composition[ composition ]
|
76
68
|
@dimension = @composition.dimension
|
77
69
|
end
|
@@ -86,9 +78,6 @@ class SY::Quantity
|
|
86
78
|
end
|
87
79
|
coerces( *Array( coerces ) )
|
88
80
|
Array( coerces_to ).each { |qnt| qnt.coerces self }
|
89
|
-
puts "Composition of the initialized instance is #{composition}." if SY::DEBUG
|
90
|
-
puts "Initialized instance is #{relative? ? :relative : :absolute}" if SY::DEBUG
|
91
|
-
puts "Initialized instance object_id is #{object_id}" if SY::DEBUG
|
92
81
|
end
|
93
82
|
|
94
83
|
# Simple quantity is one with simple composition. If nontrivial composition
|
@@ -193,21 +182,15 @@ class SY::Quantity
|
|
193
182
|
#
|
194
183
|
def measure( of: nil )
|
195
184
|
return @measure if of.nil? # act as simple getter if :of not specified
|
196
|
-
puts "#{self.inspect} asked about measure of #{of}" if SY::DEBUG
|
197
185
|
return SY::Measure.identity if of == self or of == colleague
|
198
|
-
|
186
|
+
fail SY::DimensionError, "#{self} vs. #{of}!" unless same_dimension? of
|
199
187
|
return of.measure( of: of.standard ).inverse if standardish?
|
200
188
|
m = begin
|
201
|
-
|
202
|
-
measure ||
|
203
|
-
colleague.measure ||
|
204
|
-
composition.infer_measure
|
189
|
+
measure || colleague.measure || composition.infer_measure
|
205
190
|
rescue NoMethodError
|
206
191
|
fail SY::QuantityError, "Measure of #{of} by #{self} impossible!"
|
207
192
|
end
|
208
193
|
return m if of.standardish?
|
209
|
-
puts "#{of} not standardish, obtained measure relates to #{standard}, and " +
|
210
|
-
"it will have to be extended to #{of}." if SY::DEBUG
|
211
194
|
return m * standard.measure( of: of )
|
212
195
|
end
|
213
196
|
|
@@ -266,11 +249,7 @@ class SY::Quantity
|
|
266
249
|
# Constructs a absolute magnitude of this quantity.
|
267
250
|
#
|
268
251
|
def magnitude amount
|
269
|
-
puts "self.object_id is #{object_id}" if SY::DEBUG
|
270
|
-
puts "composition is #{composition}" if SY::DEBUG
|
271
|
-
puts "Constructing #{self}#magnitude with amount #{amount}." if SY::DEBUG
|
272
252
|
Magnitude().new( of: self, amount: amount )
|
273
|
-
.tap { puts "#{self}#magnitude constructed!" if SY::DEBUG }
|
274
253
|
end
|
275
254
|
|
276
255
|
# Constructs a new unit of this quantity.
|
@@ -307,7 +286,6 @@ class SY::Quantity
|
|
307
286
|
# Quantity multiplication.
|
308
287
|
#
|
309
288
|
def * q2
|
310
|
-
puts "#{self.name} * #{q2.name}" if SY::DEBUG
|
311
289
|
rel = [ self, q2 ].any? &:relative
|
312
290
|
( SY::Composition[ self => 1 ] + SY::Composition[ q2 => 1 ] )
|
313
291
|
.to_quantity relative: rel
|
@@ -316,7 +294,6 @@ class SY::Quantity
|
|
316
294
|
# Quantity division.
|
317
295
|
#
|
318
296
|
def / q2
|
319
|
-
puts "#{self.name} / #{q2.name}" if SY::DEBUG
|
320
297
|
rel = [ self, q2 ].any? &:relative?
|
321
298
|
( SY::Composition[ self => 1 ] - SY::Composition[ q2 => 1 ] )
|
322
299
|
.to_quantity relative: rel
|
@@ -325,7 +302,6 @@ class SY::Quantity
|
|
325
302
|
# Quantity raising to a number.
|
326
303
|
#
|
327
304
|
def ** num
|
328
|
-
puts "#{self.name} ** #{num}" if SY::DEBUG
|
329
305
|
SY::Composition[ self => num ].to_quantity relative: relative?
|
330
306
|
end
|
331
307
|
|
@@ -344,8 +320,6 @@ class SY::Quantity
|
|
344
320
|
# Returns the standard quantity for this quantity's dimension.
|
345
321
|
#
|
346
322
|
def standard
|
347
|
-
puts "Dimension of this quantity is #{dimension}" if SY::DEBUG
|
348
|
-
puts "Its standard quantity is #{dimension.standard_quantity}" if SY::DEBUG
|
349
323
|
dimension.standard_quantity
|
350
324
|
end
|
351
325
|
|
@@ -397,21 +371,16 @@ class SY::Quantity
|
|
397
371
|
# Main parametrized (ie. quantity-specific) module for magnitudes.
|
398
372
|
#
|
399
373
|
def MagnitudeModule
|
400
|
-
puts "#{self}#MagnitudeModule called" if SY::DEBUG
|
401
374
|
@MagnitudeModule ||= if absolute? then
|
402
375
|
Module.new { include SY::Magnitude }
|
403
|
-
else
|
404
|
-
absolute.MagnitudeModule
|
405
|
-
end
|
376
|
+
else absolute.MagnitudeModule end
|
406
377
|
end
|
407
378
|
|
408
379
|
# Parametrized magnitude class.
|
409
380
|
#
|
410
381
|
def Magnitude
|
411
|
-
puts "#{self}#Magnitude called" if SY::DEBUG
|
412
382
|
@Magnitude or
|
413
|
-
(
|
414
|
-
mmod = MagnitudeModule()
|
383
|
+
( mmod = MagnitudeModule()
|
415
384
|
mixin = relative? ? SY::SignedMagnitude : SY::AbsoluteMagnitude
|
416
385
|
qnt_ɴ_λ = -> { name ? "#{name}@%s" : "#<Quantity:#{object_id}@%s>" }
|
417
386
|
|
@@ -439,18 +408,15 @@ class SY::Quantity
|
|
439
408
|
# Parametrized unit class.
|
440
409
|
#
|
441
410
|
def Unit
|
442
|
-
|
443
|
-
@Unit ||= ( puts "Constructing #{self}@Unit parametrized class" if SY::DEBUG
|
444
|
-
if relative? then absolute.Unit else
|
411
|
+
@Unit ||= ( if relative? then absolute.Unit else
|
445
412
|
qnt = self
|
446
413
|
ɴλ = -> { name ? "#{name}@%s" : "#<Quantity:#{object_id}@%s>" }
|
447
414
|
|
448
|
-
Class.new Magnitude() do
|
449
|
-
include SY::Unit
|
415
|
+
Class.new Magnitude() do
|
416
|
+
include SY::Unit
|
450
417
|
|
451
418
|
singleton_class.class_exec do
|
452
419
|
define_method :standard do |**nn| # Customized #standard.
|
453
|
-
puts "parametrized #{qnt}@Unit#standard called" if SY::DEBUG
|
454
420
|
@standard ||= new **nn.update( of: qnt )
|
455
421
|
end
|
456
422
|
|
@@ -462,20 +428,15 @@ class SY::Quantity
|
|
462
428
|
unit_parametrized_subclass.namespace = SY::Unit
|
463
429
|
end
|
464
430
|
end ).tap do |u|
|
465
|
-
puts "@Unit constructed, its namespace is #{u.namespace}" if SY::DEBUG
|
466
|
-
puts "its instances are #{u.namespace.instances}" if SY::DEBUG
|
467
|
-
puts "its instance names are #{u.namespace.instance_names}" if SY::DEBUG
|
468
431
|
end
|
469
432
|
end
|
470
433
|
|
471
434
|
private
|
472
435
|
|
473
436
|
def construct_colleague
|
474
|
-
puts "#{self}#construct_colleague" if SY::DEBUG
|
475
437
|
ɴ = name
|
476
438
|
ʀsuffix = SY::Quantity::RELATIVE_QUANTITY_NAME_SUFFIX
|
477
439
|
rel = relative?
|
478
|
-
puts "#{self} is #{rel ? 'relative' : 'absolute'}" if SY::DEBUG
|
479
440
|
# Here, it is impossible to rely on Composition::QUANTITY_TABLE –
|
480
441
|
# on the contrary, the table relies on Quantity#colleague.
|
481
442
|
constr_ɴ = ->( ɴ, ʀ ) { ç.new composition: composition, ɴ: ɴ, relative: ʀ }
|
data/lib/sy/signed_magnitude.rb
CHANGED
@@ -7,31 +7,20 @@ module SY::SignedMagnitude
|
|
7
7
|
# :amount argument. Amount is allowed to be negative.
|
8
8
|
#
|
9
9
|
def initialize( of: nil, amount: nil )
|
10
|
-
puts "Constructing AbsoluteMagnitude of #{of}, amount: #{amount}" if SY::DEBUG
|
11
10
|
fail ArgumentError, "Quantity (:of) argument missing!" if of.nil?
|
12
11
|
@quantity = of
|
13
12
|
@amount = case amount
|
14
|
-
when Numeric then
|
15
|
-
|
16
|
-
amount
|
17
|
-
when nil then
|
18
|
-
puts "This amount is 'nil', using 1 instead" if SY::DEBUG
|
19
|
-
1
|
13
|
+
when Numeric then amount
|
14
|
+
when nil then 1
|
20
15
|
else
|
21
16
|
begin
|
22
|
-
puts "Amount #{amount} will be reframed to #{@quantity}" if SY::DEBUG
|
23
17
|
amount.( @quantity ).amount
|
24
|
-
rescue NameError, NoMethodError
|
25
|
-
puts "fail, amount #{amount} will be used directly" if SY::DEBUG
|
26
|
-
amount
|
27
|
-
end
|
18
|
+
rescue NameError, NoMethodError; amount end
|
28
19
|
end
|
29
20
|
end
|
30
21
|
|
31
22
|
# Addition.
|
32
23
|
#
|
33
|
-
# TODO: Figure out which module comes on the top in Quantity@Magnitude, whether Magnitude
|
34
|
-
# or SignedMagnitude, and therefore, whether it is necessary to adjust this method.
|
35
24
|
def + m2
|
36
25
|
return magnitude( amount + m2.amount ) if quantity == m2.quantity
|
37
26
|
return quantity.absolute.magnitude( amount + m2.amount ) if
|
@@ -42,7 +31,6 @@ module SY::SignedMagnitude
|
|
42
31
|
|
43
32
|
# Subtraction.
|
44
33
|
#
|
45
|
-
# TODO: ditto
|
46
34
|
def - m2
|
47
35
|
return magnitude( amount - m2.amount ) if m2.quantity == quantity.relative
|
48
36
|
return quantity.relative.magnitude( amount - m2.amount ) if
|
data/lib/sy/unit.rb
CHANGED
@@ -46,16 +46,12 @@ module SY::Unit
|
|
46
46
|
w = SY::ExpressibleInUnits::COLLISION_WARNING
|
47
47
|
SY::ExpressibleInUnits.included_in.each do |modul|
|
48
48
|
im = modul.instance_methods
|
49
|
-
# puts ɱ, "class: #{ɱ.class}"
|
50
|
-
# puts im.size
|
51
|
-
# puts down
|
52
|
-
# puts im.include? down
|
53
49
|
warn w % [down, modul] if im.include? down
|
54
50
|
abbrev = new_instance.abbreviation
|
55
51
|
warn w % [abbrev, modul] if im.include? abbrev
|
56
52
|
end
|
57
53
|
end
|
58
|
-
up.to_sym
|
54
|
+
up.to_sym
|
59
55
|
end
|
60
56
|
|
61
57
|
# We'll now define all the prefix methods on the target (#mili, #mega...),
|
@@ -94,7 +90,6 @@ module SY::Unit
|
|
94
90
|
# special meaning of setting the relationship of that quantity.
|
95
91
|
#
|
96
92
|
def standard( of: nil, **nn )
|
97
|
-
puts "Constructing a standard unit of #{of}." if SY::DEBUG
|
98
93
|
fail ArgumentError, ":of argument missing!" if of.nil?
|
99
94
|
qnt = SY::Quantity.instance( of )
|
100
95
|
nn.empty? ? qnt.standard_unit : qnt.new_standard_unit( **nn )
|
@@ -110,7 +105,7 @@ module SY::Unit
|
|
110
105
|
# Full list of known unit names and unit abbreviations.
|
111
106
|
#
|
112
107
|
def known_symbols
|
113
|
-
|
108
|
+
instances.names( false ).map( &:downcase ) + abbreviations.keys
|
114
109
|
end
|
115
110
|
|
116
111
|
# Parses an SPS, curring it with known unit names and abbreviations,
|
@@ -156,13 +151,6 @@ module SY::Unit
|
|
156
151
|
def initialize( short: nil, warns: true, **nn )
|
157
152
|
@abbreviation = short.to_sym if short
|
158
153
|
@warns = warns # does this unit care about blatant name collisions?
|
159
|
-
|
160
|
-
# FIXME: Here, we would have to watch out for :amount being set
|
161
|
-
# if it is a number, amount is in standard units
|
162
|
-
# however, if it is a magnitude, especially one of another equidimensional quantity,
|
163
|
-
# it estableshes a relationship between this and that quantity. It means that
|
164
|
-
# the unit amount automatically becomes ... one ... and such relationship can
|
165
|
-
# only be established for standard quantity
|
166
154
|
super nn
|
167
155
|
end
|
168
156
|
|
@@ -269,7 +257,5 @@ module SY::Unit
|
|
269
257
|
|
270
258
|
# String describing this class.
|
271
259
|
#
|
272
|
-
def
|
273
|
-
"Unit"
|
274
|
-
end
|
260
|
+
def çς; "Unit" end
|
275
261
|
end # class SY::Unit
|
data/lib/sy/version.rb
CHANGED
data/test/sy_test.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
#! /usr/bin/ruby
|
2
2
|
# encoding: utf-8
|
3
3
|
|
4
|
-
#
|
4
|
+
# *****************************************************************
|
5
5
|
# THIS IS SPEC-STYLE TEST FILE FOR SY PHYSICAL UNITS LIBRARY
|
6
|
-
#
|
6
|
+
# *****************************************************************
|
7
7
|
|
8
8
|
# The following will load Ruby spec-style library
|
9
9
|
require 'mathn'
|
10
10
|
require 'minitest/autorun'
|
11
11
|
|
12
12
|
# The following will load SY library
|
13
|
-
require 'sy'
|
14
|
-
|
13
|
+
# require 'sy'
|
14
|
+
require './../lib/sy'
|
15
15
|
|
16
|
-
#
|
16
|
+
# *****************************************************************
|
17
17
|
# THE SPECIFICATIONS START HERE
|
18
|
-
#
|
18
|
+
# *****************************************************************
|
19
19
|
|
20
20
|
describe SY do
|
21
21
|
it "should have basic assets" do
|
@@ -253,7 +253,7 @@ describe SY::Quantity, SY::Magnitude do
|
|
253
253
|
1.mm.to_s.must_equal "0.001.m"
|
254
254
|
1.mm.inspect.must_equal "#<±Magnitude: 0.001.m >"
|
255
255
|
1.µs.inspect.must_equal "#<±Magnitude: 1e-06.s >"
|
256
|
-
|
256
|
+
|
257
257
|
SY::Area.dimension.must_equal SY.Dimension( :L² )
|
258
258
|
SY::Area.composition.must_equal SY::Composition[ SY::Length => 2 ]
|
259
259
|
|
@@ -298,7 +298,7 @@ describe SY::Quantity, SY::Magnitude do
|
|
298
298
|
|
299
299
|
q1.relative?.must_equal true
|
300
300
|
q2.relative?.must_equal true
|
301
|
-
|
301
|
+
|
302
302
|
q1.object_id.must_equal q2.object_id
|
303
303
|
( 1.s⁻¹ ).quantity.object_id.must_equal ( 1 / 1.s ).quantity.object_id
|
304
304
|
( 1 / 1.s ).must_equal 1.s⁻¹
|
@@ -312,9 +312,10 @@ describe SY::Quantity, SY::Magnitude do
|
|
312
312
|
rescue
|
313
313
|
end
|
314
314
|
end.must_include :M
|
315
|
-
SY::Unit.
|
315
|
+
SY::Unit.instances.names( false ).must_include :MOLE
|
316
316
|
# Avogadro's number is defined directly in SY
|
317
|
-
1.mol.quantity.object_id
|
317
|
+
1.mol.quantity.object_id
|
318
|
+
.must_equal SY::Nᴀ.unit.( SY::MoleAmount ).quantity.object_id
|
318
319
|
SY::Nᴀ.unit.( SY::MoleAmount ).must_equal 1.mol
|
319
320
|
0.7.mol.l⁻¹.amount.must_equal 0.7
|
320
321
|
1.M.must_equal 1.mol.l⁻¹.( SY::Molarity )
|
@@ -325,7 +326,6 @@ describe SY::Quantity, SY::Magnitude do
|
|
325
326
|
# Avogadro's number is defined directly in SY
|
326
327
|
1.mol.must_equal SY::Nᴀ.unit.( SY::MoleAmount )
|
327
328
|
|
328
|
-
|
329
329
|
0.7.M.must_equal 0.7.mol.l⁻¹.( SY::Molarity )
|
330
330
|
# (if #is_actually! conversion method is not used, current
|
331
331
|
# implementation will refuse to compare different quantities,
|
@@ -353,10 +353,17 @@ describe SY::Quantity, SY::Magnitude do
|
|
353
353
|
# watt
|
354
354
|
( 1.V * 1.A ).( SY::Power ).must_be_within_epsilon 1.W, 1e-9
|
355
355
|
|
356
|
-
#
|
357
|
-
|
358
|
-
|
356
|
+
# Custom unit creation
|
357
|
+
XOXO = SY::Unit.of SY::Volume, amount: 1.l
|
358
|
+
assert_equal 1.l.( SY::Volume ), 1.xoxo.( SY::Volume )
|
359
359
|
|
360
|
+
# TRIPLE_POINT_OF_WATER
|
361
|
+
assert_equal SY::TRIPLE_POINT_OF_WATER, 0.°C.( SY::Temperature )
|
362
|
+
assert_equal 273.15, 0.°C.in( :K )
|
363
|
+
assert_equal SY::Unit.instance( :SECOND ), SY::Unit.instance( :second )
|
364
|
+
assert_equal SY::TRIPLE_POINT_OF_WATER, 0.°C # coercion behavior
|
365
|
+
|
366
|
+
# other tests
|
360
367
|
assert_equal 1.m, 1.s * 1.m.s⁻¹
|
361
368
|
assert_equal 1.µM.s⁻¹, 1.µM / 1.s
|
362
369
|
assert_equal 1.m.s⁻¹, 1.m.s( -1 )
|
@@ -367,64 +374,39 @@ describe SY::Quantity, SY::Magnitude do
|
|
367
374
|
assert_equal SY::Amount( 1 ), 1.µM / ( 1.µM + 0.µM )
|
368
375
|
assert_equal 1.µM, 1.µM * 1.µM / ( 1.µM + 0.µM )
|
369
376
|
assert_in_epsilon 1.µM, 1.µmol / 1.dm( 3 ).( SY::LitreVolume )
|
370
|
-
|
377
|
+
|
371
378
|
assert_equal SY::Molarity.relative, 1.mol.l⁻¹.quantity
|
372
379
|
assert_equal SY::MoleAmount.relative, 1.M.l.quantity
|
373
380
|
|
381
|
+
|
374
382
|
assert_equal 1 / SY::Time, 1 / SY::Time
|
375
383
|
assert_equal 1 / SY::Time.relative, 1 / SY::Time
|
376
384
|
assert_equal ( 1 / SY::Time.relative ), 1.mol.s⁻¹.( 1 / SY::Time ).quantity
|
377
385
|
assert_equal ( 1 / SY::Time ).object_id,
|
378
|
-
|
386
|
+
( 1.0.µmol.min⁻¹.mg⁻¹ * 100.kDa ).( 1 / SY::Time ).quantity.object_id
|
379
387
|
assert_equal SY::Time.magnitude( 1 ), SY::SECOND
|
380
|
-
|
388
|
+
end
|
389
|
+
|
390
|
+
describe "pretty representation" do
|
391
|
+
it "should" do
|
392
|
+
( 1.0.m / 3.s ).to_s.must_be_kind_of String
|
393
|
+
( 1.0.m / 3.s ).to_s.must_equal "0.333.m.s⁻¹"
|
394
|
+
|
395
|
+
( 1.m / 7.01e7.s ).to_s.must_equal( "1.43e-08.m.s⁻¹" )
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
describe "matrix integration" do
|
400
|
+
it "should" do
|
401
|
+
assert_equal Matrix[[60.mM], [60.mM]], Matrix[[1e-03.s⁻¹.M], [1e-3.s⁻¹.M]] * 60.s
|
381
402
|
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
assert_equal 1.l.( SY::Volume ), 1.xoxo.( SY::Volume )
|
390
|
-
assert_equal SY::TRIPLE_POINT_OF_WATER, 0.°C.( SY::Temperature )
|
391
|
-
assert_equal 273.15, 0.°C.in( :K )
|
392
|
-
assert_equal SY::Unit.instance( :SECOND ), SY::Unit.instance( :second )
|
393
|
-
assert_equal SY::TRIPLE_POINT_OF_WATER, 0.°C # coercion behavior
|
394
|
-
assert 2.°C.eql?( 1.°C + 1.K )
|
395
|
-
assert ( 1.°C - 1.°C ).eql?( 0.K )
|
396
|
-
assert_equal :raised, begin
|
397
|
-
1.°C + 1.°C
|
398
|
-
:nothing_raised
|
399
|
-
rescue QuantityError
|
400
|
-
:raised
|
401
|
-
end
|
402
|
-
assert_equal :raised, begin
|
403
|
-
1.K + 1.°C
|
404
|
-
:nothing_raised
|
405
|
-
rescue QuantityError
|
406
|
-
:raised
|
407
|
-
end
|
408
|
-
assert_equal :raised, begin
|
409
|
-
1.K - 1.°C
|
410
|
-
:nothing_raised
|
411
|
-
rescue QuantityError
|
412
|
-
:raised
|
413
|
-
end
|
414
|
-
assert 1.mm.K⁻¹.eql?( 1.mm.°C⁻¹ )
|
415
|
-
assert 1.mm.K.eql?( 1.mm.°C )
|
416
|
-
assert_equal :raised, begin
|
417
|
-
1.mm / 1.°C
|
418
|
-
:nothing_raised
|
419
|
-
rescue QuantityError
|
420
|
-
:raised
|
421
|
-
end
|
422
|
-
assert_equal :raised, begin
|
423
|
-
1.mm * 1.°C
|
424
|
-
:nothing_raised
|
425
|
-
rescue QuantityError
|
426
|
-
:raised
|
427
|
-
end
|
403
|
+
assert_equal Matrix[[5.m]], Matrix[[1.m.s⁻¹, 2.m.s⁻¹]] * Matrix.column_vector( [1.s, 2.s] )
|
404
|
+
assert_equal Matrix[[2.m, 3.m], [4.m, 5.m]],
|
405
|
+
Matrix[[1.m, 2.m], [3.m, 4.m]] + Matrix[[1.m, 1.m], [1.m, 1.m]]
|
406
|
+
assert_equal Matrix[[5.µM]], Matrix[[1.µM]] + Matrix[[2.µM.s⁻¹]] * Matrix[[2.s]]
|
407
|
+
assert_equal Matrix[[1.s]], Matrix[[1]] * 1.s
|
408
|
+
assert_equal Matrix[[1.s]], 1.s * Matrix[[1]]
|
409
|
+
end
|
428
410
|
end
|
429
411
|
end
|
430
412
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boris Stitnicky
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|