sy 2.1.2 → 2.1.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|