sy 2.0.4 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fd4b854cf2fceae1fb55d2e657f219807f88f6c6
4
- data.tar.gz: 730fec5dad579f42e482d49cbaad66b56e901685
3
+ metadata.gz: 666dbe08efdd97d407e931045726b9668f5bf3c2
4
+ data.tar.gz: aa13e418672f7223bcdb63683eb42c511974b2f2
5
5
  SHA512:
6
- metadata.gz: 2b2c9f2994e1d30db45eeeed40f952aad46e619a3935db909b2446f2b08f169525216cca37f49747abaf3dbc30213f38da505dd3e0ef0d4e84e678bf00d67807
7
- data.tar.gz: ca82955c039d47f775292f3b1ee9c92ef6cba91ea0b0b99af4ae4f2666f90b0f9366b267b8e98299d195d94902d82dcb50f68fb632a6e32a3fb9fe4d0f314030
6
+ metadata.gz: deb58fde2b519570d6fc891a9e259aeafca50d541e6807c26075e4e1cd7415355378070baa05f231d449a36252d8cbd286120fdd37245fde87b79501a2e19dd2
7
+ data.tar.gz: 695f6feedb083dd82b35ebc7720a6aa89586dba97bee1ce4ff0a28a93fcf012e1957f0e7a8cabd618e328b89226f272eb5673dec1770c0ffcc211c1f847ad420
@@ -1,19 +1,30 @@
1
1
  # -*- coding: utf-8 -*-
2
- # Qualities specific to absolute magnitudes.
2
+ # Qualities specific to absolute magnitudes (mixin).
3
+ #
4
+ # Absolute magnitude may not be negative – physical amounts cannot have
5
+ # negative number of unit objects. (<em>Difference</me> between magnitudes
6
+ # (relative magnitude) can be positive as well as negative.
7
+ #
8
+ # While ordinary #+ and #- methods of absolute magnitudes return relative
9
+ # magnitudes, absolute magnitudes have additional methods #add and #subtract,
10
+ # that return absolute magnitudes (it is the responsibility of the caller to
11
+ # avoid negative results). Furthermore, absolute magnitudes have one more
12
+ # special method #take, which perfoms #subtract whilst protecting against
13
+ # subtraction of more than, there is to take.
3
14
  #
4
15
  module SY::AbsoluteMagnitude
5
16
  # Absolute magnitude constructor takes :quantity (alias :of) named argument,
6
17
  # and :amount named argument, where amount must be nonnegative.
7
18
  #
8
- def initialize( of: ( fail ArgumentError, ":of argument missing!" ),
9
- amount: nil )
19
+ def initialize( of: nil, amount: nil )
20
+ fail ArgumentError, "Quantity (:of) argument missing!" if of.nil?
10
21
  @quantity = of
11
22
  @amount = case amount
12
23
  when Numeric then amount
13
24
  when nil then 1
14
25
  else
15
26
  begin
16
- amount.amount
27
+ amount.( @quantity ).amount
17
28
  rescue NameError, NoMethodError
18
29
  amount
19
30
  end
@@ -2,8 +2,114 @@
2
2
  # This mixin provides ability to respond to SY unit symbol methods.
3
3
  #
4
4
  module SY::ExpressibleInUnits
5
+ COLLISION_WARNING = "Unit %s collision, method already defined on %s!"
6
+ REDEFINE_WARNING = "Method %s being defined on %s shadows SY unit method!"
5
7
  RecursionError = Class.new StandardError
6
8
 
9
+ # This is a mixin for the target class of this mixin, that causes it to warn
10
+ # upon detecting newly defined methods shadowing the SY unit methods.
11
+ #
12
+ module DetectRedefine
13
+ def method_added ß
14
+ # warn "#{self}: method added: :#{ß}"
15
+ uu = ::SY::ExpressibleInUnits.known_units
16
+ nn = uu.map &:name
17
+ aa = uu.map &:abbreviation
18
+ ꜧ = Hash[ nn.zip( uu ) ].merge Hash[ aa.zip( uu ) ]
19
+ w = ::SY::ExpressibleInUnits::REDEFINE_WARNING % [ ß, self ]
20
+ if nn.include? ß then
21
+ if instance_methods.include? ß then
22
+ im = instance_method ß
23
+ warn w unless ::SY::ExpressibleInUnits.method_family.include? im if
24
+ ꜧ[ß].warns? unless instance_variable_get( :@no_collision ) == ß
25
+ instance_variable_set( :@no_collision, nil ) # FIXME: This is too clumsy
26
+ else
27
+ warn w if ꜧ[ß].warns?
28
+ end
29
+ end
30
+ if aa.include? ß then
31
+ if instance_methods.include? ß then
32
+ im = instance_method ß
33
+ warn w unless ::SY::ExpressibleInUnits.method_family.include? im if
34
+ ꜧ[ß].warns? unless instance_variable_get( :@no_collision ) == ß
35
+ instance_variable_set( :@no_collision, nil ) # FIXME: This is too clumsy
36
+ else
37
+ warn w if ꜧ[ß].warns?
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ class << self
44
+ # #included hook of this module is set to perfom a casual check for blatant
45
+ # name collisions between SY::Unit-implied methods, and existing methods of
46
+ # the include receiver.
47
+ #
48
+ def included receiver
49
+ included_in << receiver # keep track of where the mixin has been included
50
+ # Warn if the receiver has potentially colliding methods.
51
+ inst_methods = receiver.instance_methods
52
+ w = COLLISION_WARNING % ["%s", receiver]
53
+ known_units.each do |unit|
54
+ next unless unit.warns?
55
+ name, short = unit.name, unit.abbreviation
56
+ warn w % "name method ##{name}" if inst_methods.include? name
57
+ warn w % "abbreviation method ##{short}" if inst_methods.include? short
58
+ end
59
+ # Warn if shadowing methods are defined on the receiver later.
60
+ if receiver.is_a? Class
61
+ receiver.extend ::SY::ExpressibleInUnits::DetectRedefine
62
+ end
63
+ end
64
+
65
+ # Modules in which this mixin has been included.
66
+ #
67
+ def included_in
68
+ @included_in ||= []
69
+ end
70
+
71
+ # Currently defined unit instances, if any.
72
+ #
73
+ def known_units
74
+ unit_namespace = begin
75
+ SY::Unit
76
+ rescue NameError
77
+ return [] # no SY::Unit yet
78
+ end
79
+ begin
80
+ unit_namespace.instances
81
+ rescue NoMethodError
82
+ [] # no #instances method defined yet
83
+ end
84
+ end
85
+
86
+ # All methods defined by this mixin.
87
+ #
88
+ def method_family
89
+ @method_family ||= []
90
+ end
91
+
92
+ # Find unit based on name / abbreviation.
93
+ #
94
+ def find_unit ς
95
+ known_units.find { |u| u.name.to_s == ς || u.short.to_s == ς }
96
+ end
97
+
98
+ # Return prefix method or empty string, if prefix method not necessary.
99
+ #
100
+ def prefix_method_string prefix
101
+ puts "About to call PREFIX TABLE.to_full with #{prefix}" if SY::DEBUG
102
+ full_prefix = SY::PREFIX_TABLE.to_full( prefix )
103
+ full_prefix == '' ? '' : ".#{full_prefix}"
104
+ end
105
+
106
+ # Return exponentiation string (suffix) or empty ς if not necessary.
107
+ #
108
+ def exponentiation_string exp
109
+ exp == 1 ? '' : " ** #{exp}"
110
+ end
111
+ end
112
+
7
113
  def method_missing ß, *args, &block
8
114
  return self if ß.to_s =~ /begin|end/ # 3rd party bug workaround
9
115
  super if ß.to_s =~ /to_.+/ # dissmiss :to_..., esp. :to_ary
@@ -12,7 +118,12 @@ module SY::ExpressibleInUnits
12
118
  puts "Method missing: '#{ß}'" if SY::DEBUG
13
119
  prefixes, units, exps = parse_unit_symbol ß
14
120
  # Define the unit method on self.class:
15
- ç.module_eval write_unit_method( ß, prefixes, units, exps )
121
+ # I'D HAVE TO PERFORM THE COLLISION CHECK HERE
122
+ # IF NO COLLISION, INFORM THE SUBSEQUENT METHOD DEFINED CALL ON
123
+ # SELF.CLASS
124
+ self.class.instance_variable_set "@no_collision", ß # FIXME: This is too clumsy
125
+ self.class.module_eval write_unit_method( ß, prefixes, units, exps )
126
+ SY::ExpressibleInUnits.method_family << self.class.instance_method( ß )
16
127
  end
17
128
  rescue NameError => err
18
129
  puts "NameError raised: #{err}" if SY::DEBUG
@@ -27,8 +138,10 @@ module SY::ExpressibleInUnits
27
138
  def respond_to_missing? ß, *args, &block
28
139
  # dismiss :to_... methods and /begin|end/ (3rd party bug workaround)
29
140
  return false if ß.to_s =~ /to_.+|begin|end/
30
- begin
31
- anti_recursion_exec token: ß, var: :@SY_Units_rmiss do parse_unit ß end
141
+ !! begin
142
+ anti_recursion_exec token: ß, var: :@SY_Units_rmiss do
143
+ parse_unit_symbol ß
144
+ end
32
145
  rescue NameError, SY::ExpressibleInUnits::RecursionError
33
146
  false
34
147
  else
@@ -50,26 +163,13 @@ module SY::ExpressibleInUnits
50
163
  # Arrays must be of equal length. (Note: 'ß' is 'symbol', 'ς' is 'string')
51
164
  #
52
165
  def write_unit_method ß, prefixes, units, exponents
53
- known_units = SY::Unit.instances
54
- # A procedure to find unit based on name or abbreviation:
55
- find_unit = lambda do |ς|
56
- known_units.find { |u| u.name.to_s == ς || u.short.to_s == ς }
57
- end
58
- # Return prefix method or empty ς if not necessary.
59
- prefix_method_ς = lambda do |prefix|
60
- puts "About to call PREFIX TABLE.to_full with #{prefix}" if SY::DEBUG
61
- full_prefix = SY::PREFIX_TABLE.to_full( prefix )
62
- full_prefix == '' ? '' : ".#{full_prefix}"
63
- end
64
- # Return exponentiation string (suffix) or empty ς if not necessary.
65
- exponentiation_ς = lambda do |exp| exp == 1 ? '' : " ** #{exp}" end
66
166
  # Prepare prefix / unit / exponent triples for making factor strings:
67
167
  triples = [ prefixes, units, exponents ].transpose
68
168
  # A procedure for triple processing before use:
69
169
  process_triple = lambda do |pfx, unit_ς, exp|
70
- [ find_unit.( unit_ς ).name.to_s.upcase,
71
- prefix_method_ς.( pfx ),
72
- exponentiation_ς.( exp ) ]
170
+ [ ::SY::ExpressibleInUnits.find_unit( unit_ς ).name.to_s.upcase,
171
+ ::SY::ExpressibleInUnits.prefix_method_string( pfx ),
172
+ ::SY::ExpressibleInUnits.exponentiation_string( exp ) ]
73
173
  end
74
174
  # Method skeleton:
75
175
  if triples.size == 1 && triples.first[-1] == 1 then
@@ -2,9 +2,9 @@
2
2
  # Here, fixed assets of the main module are set up.
3
3
  #
4
4
  module SY
5
- QuantityError = Class.new StandardError # mixing incompatible quantities
6
- DimensionError = Class.new StandardError # mixing incompatible dimensions
7
- MagnitudeError = Class.new StandardError # creating impossible magnitude
5
+ QuantityError = Class.new TypeError # mixing incompatible quantities
6
+ DimensionError = Class.new TypeError # mixing incompatible dimensions
7
+ MagnitudeError = Class.new TypeError # creating impossible magnitude
8
8
 
9
9
  BASE_DIMENSIONS = { # Basic physical dimensions.
10
10
  L: :LENGTH,
@@ -273,5 +273,12 @@ module SY
273
273
  SY::Magnitude.of qnt, args
274
274
  end
275
275
 
276
- module_function :Dimension, :Quantity, :Unit, :Magnitude
276
+ # Convenitence constructor of amounts (SY::Amount if the standard
277
+ # dimensionless quantity of SY).
278
+ #
279
+ def Amount number
280
+ SY::Amount.relative.magnitude( number )
281
+ end
282
+
283
+ module_function :Dimension, :Quantity, :Unit, :Magnitude, :Amount
277
284
  end
data/lib/sy/magnitude.rb CHANGED
@@ -1,17 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
- # This class here represents absolute magnitude – physical number of unit
3
- # objects, that make up the amount of some metrological quantity. Amount of
4
- # an absolute magnitudes may not be negative – physical amounts cannot have
5
- # negative number of unit objects. But as for the <em>difference</me> between
6
- # magnitudes, this can be positive as well as negative – relative magnitudes
7
- # are used for this purpose.
8
- #
9
- # While ordinary #+ and #- methods of absolute magnitudes return relative
10
- # magnitudes, absolute magnitudes have additional methods #add and #subtract,
11
- # that return absolute magnitudes (it is the responsibility of the caller to
12
- # avoid negative results). Furthermore, absolute magnitudes have one more
13
- # special method #take, which perfoms #subtract whilst protecting against
14
- # subtraction of more than, there is to take.
2
+ # This module stores assets pertaining to a magnitude – be it absolute magnitude
3
+ # (physical number of unit objects), or relative magnitude (magnitude differnce).
15
4
  #
16
5
  module SY::Magnitude
17
6
  class << self
@@ -169,6 +158,18 @@ module SY::Magnitude
169
158
  end
170
159
  end
171
160
 
161
+ # Same magnitudes <em>and</em> same (#eql) quantities.
162
+ #
163
+ def eql other
164
+ raise NotImplementedError
165
+ end
166
+
167
+ # Percent operator (remainder after division)
168
+ #
169
+ def %
170
+ raise NotImplementedError
171
+ end
172
+
172
173
  # Type coercion for magnitudes.
173
174
  #
174
175
  def coerce m2
@@ -192,8 +193,7 @@ module SY::Magnitude
192
193
  "method collision with another library?"
193
194
  end
194
195
  when SY::Magnitude then
195
- return amount / m2.amount if quantity == m2.quantity
196
- amount / m2.( quantity ).amount # reframe before division
196
+ quantity.measure( of: m2.quantity ).w.( amount ) / m2.amount
197
197
  else
198
198
  raise TypeError, "Unexpected type for Magnitude#in method! (#{m2.class})"
199
199
  end
data/lib/sy/quantity.rb CHANGED
@@ -12,7 +12,7 @@ class SY::Quantity
12
12
  RELATIVE_QUANTITY_NAME_SUFFIX = "±"
13
13
 
14
14
  attr_reader :MagnitudeModule, :Magnitude, :Unit
15
- attr_reader :dimension, :composition
15
+ attr_reader :dimension, :composition, :units
16
16
 
17
17
  class << self
18
18
  # Dimension-based quantity constructor. Examples:
@@ -58,6 +58,7 @@ class SY::Quantity
58
58
  #
59
59
  def initialize( relative: nil, composition: nil, of: nil, measure: nil, amount: nil, **nn )
60
60
  puts "Quantity init relative: #{relative}, composition: #{composition}, measure: #{measure}, #{nn}" if SY::DEBUG
61
+ @units = [] # array of units as favored by this quantity
61
62
  @relative = relative
62
63
  if composition.nil? then
63
64
  puts "Composition not given, dimension expected." if SY::DEBUG
@@ -233,12 +234,6 @@ class SY::Quantity
233
234
  Unit().standard
234
235
  end
235
236
 
236
- # Presents an array of units ordered as favored by this quantity.
237
- #
238
- def units
239
- @units ||= []
240
- end
241
-
242
237
  # Constructs a new absolute magnitude of this quantity.
243
238
  #
244
239
  def magnitude amount
@@ -248,7 +243,8 @@ class SY::Quantity
248
243
  # Constructs a new unit of this quantity.
249
244
  #
250
245
  def unit **nn
251
- Unit().new( nn.update( of: self ) ).tap { |u| ( units << u ).uniq! }
246
+ Unit().new( nn.update( of: self ) )
247
+ .tap { |u| ( units << u ).uniq! } # add it to the @units array
252
248
  end
253
249
 
254
250
  # Constructor of a new standard unit (replacing current @standard_unit).
@@ -380,7 +376,7 @@ class SY::Quantity
380
376
  def Magnitude
381
377
  @Magnitude or
382
378
  ( mmod = MagnitudeModule()
383
- mixin = relative? ? ::SY::SignedMagnitude : ::SY::AbsoluteMagnitude
379
+ mixin = relative? ? SY::SignedMagnitude : SY::AbsoluteMagnitude
384
380
  qnt_ɴ_λ = -> { name ? "#{name}@%s" : "#<Quantity:#{object_id}@%s>" }
385
381
 
386
382
  @Magnitude = Class.new do
@@ -1,22 +1,21 @@
1
- #encoding: utf-8
2
-
3
- # Qualities specific to relative magnitudes.
1
+ # -*- coding: utf-8 -*-
2
+ # Qualities specific to relative magnitudes (mixin).
4
3
  #
5
4
  module SY::SignedMagnitude
6
5
  # Relative magnitude constructor takes :quantity (alias :of) argument and
7
6
  # :amount argument. Amount is allowed to be negative.
8
7
  #
9
- def initialize **named_args
10
- @quantity = named_args[:quantity] || named_args[:of]
11
- amnt = named_args[:amount]
12
- @amount = case amnt
13
- when Numeric then amnt
8
+ def initialize( of: nil, amount: nil )
9
+ fail ArgumentError, "Quantity (:of) argument missing!" if of.nil?
10
+ @quantity = of
11
+ @amount = case amount
12
+ when Numeric then amount
14
13
  when nil then 1
15
14
  else
16
15
  begin
17
- amnt.amount
16
+ amount.( @quantity ).amount
18
17
  rescue NameError, NoMethodError
19
- amnt
18
+ amount
20
19
  end
21
20
  end
22
21
  end
data/lib/sy/unit.rb CHANGED
@@ -4,6 +4,8 @@
4
4
  # of a metrological quantity.
5
5
  #
6
6
  module SY::Unit
7
+ PROTECTED_NAMES = [ "kilogram" ]
8
+
7
9
  def self.pre_included target
8
10
  class << target
9
11
  # Overriding this method from NameMagic mixin ensures, that all Unit
@@ -12,29 +14,29 @@ module SY::Unit
12
14
  def namespace
13
15
  SY::Unit
14
16
  end
17
+ end
18
+ end # def self.pre_included
15
19
 
16
- # Tweaking instance accessor from NameMagic to make it accept unit
17
- # abbreviations and unit names regardless of capitalization
18
- #
19
- def instance arg
20
- begin
21
- super # let's first try the original method
22
- rescue NameError # if we fail...
23
- begin # second in order, let's try whether it's an abbreviation
24
- super instances.find { |inst|
25
- inst.abbreviation.to_s == arg.to_s if inst.abbreviation
26
- }
27
- rescue NameError, TypeError
28
- begin # finally, let's try upcase if we have all-downcase arg
29
- super arg.to_s.upcase
30
- rescue NameError # if not, tough luck
31
- raise NameError, "Unknown unit symbol: #{which}"
32
- end
33
- end
20
+ # Tweaking instance accessor from NameMagic to make it accept unit
21
+ # abbreviations and unit names regardless of capitalization
22
+ #
23
+ def self.instance arg
24
+ begin
25
+ super # let's first try the original method
26
+ rescue NameError # if we fail...
27
+ begin # second in order, let's try whether it's an abbreviation
28
+ super instances.find { |inst|
29
+ inst.abbreviation.to_s == arg.to_s if inst.abbreviation
30
+ }
31
+ rescue NameError, TypeError
32
+ begin # finally, let's try upcase if we have all-downcase arg
33
+ super arg.to_s.upcase
34
+ rescue NameError # if not, tough luck
35
+ raise NameError, "Unknown unit symbol: #{which}"
34
36
  end
35
37
  end
36
- end # class << target
37
- end # def self.pre_included
38
+ end
39
+ end # def self.instance
38
40
 
39
41
  def self.included target
40
42
  target.class_exec do
@@ -42,13 +44,30 @@ module SY::Unit
42
44
  name_set_closure do |name, new_instance, old_name|
43
45
  ɴ = name.to_s
44
46
  up, down = ɴ.upcase, ɴ.downcase
47
+ # Check case (only all-upper or all-lower is acceptable).
45
48
  unless ɴ == up || ɴ = down
46
49
  raise NameError, "Unit must be either all-upper or all-lower case!"
47
50
  end
51
+ # Reject the names starting with a full prefix.
48
52
  conflicter = SY::PREFIX_TABLE.full_prefixes
49
53
  .find { |prefix| down.starts_with? prefix unless prefix.empty? }
50
54
  raise NameError, "Name #{ɴ} starts with #{conflicter}- prefix" unless
51
- down == 'kilogram' if conflicter
55
+ SY::Unit::PROTECTED_NAMES.include? down if conflicter
56
+ # Warn about the conflicts in modules where the SY::ExpressibleInUnits
57
+ # mixin is included.
58
+ if new_instance.warns? then
59
+ w = ::SY::ExpressibleInUnits::COLLISION_WARNING
60
+ ::SY::ExpressibleInUnits.included_in.each do |ɱ|
61
+ im = ɱ.instance_methods
62
+ # puts ɱ, "class: #{ɱ.class}"
63
+ # puts im.size
64
+ # puts down
65
+ # puts im.include? down
66
+ warn w % [down, ɱ] if im.include? down
67
+ abbrev = new_instance.abbreviation
68
+ warn w % [abbrev, ɱ] if im.include? abbrev
69
+ end
70
+ end
52
71
  up.to_sym
53
72
  end
54
73
 
@@ -80,17 +99,8 @@ module SY::Unit
80
99
  class << self
81
100
  # Constructor of units of a given quantity.
82
101
  #
83
- def of *args
84
- = args.extract_options!
85
- qnt = case args.size
86
- when 0 then
87
- ꜧ.must_have( :quantity, syn!: :of )
88
- ꜧ.delete :quantity
89
- when 1 then args.shift
90
- else
91
- raise AErr, "Too many ordered arguments!"
92
- end
93
- return qnt.unit *( ꜧ.empty? ? args : args << ꜧ )
102
+ def of quantity, **nn
103
+ quantity.unit **nn
94
104
  end
95
105
 
96
106
  # Standard unit constructor. In absence of other named arguments, standard
@@ -132,7 +142,13 @@ module SY::Unit
132
142
  # Unlike ordinary magnitudes, units can have names and abbreviations.
133
143
  #
134
144
  attr_reader :abbreviation
135
- alias :short :abbreviation
145
+ alias short abbreviation
146
+
147
+ # Whether the unit warns when the module in which unit method mixin is
148
+ # included contains blatant name collisions with this unit name/abbreviation.
149
+ #
150
+ attr_accessor :warns
151
+ alias warns? warns
136
152
 
137
153
  # Unit abbreviation setter.
138
154
  #
@@ -153,16 +169,20 @@ module SY::Unit
153
169
  ɴ = super
154
170
  return ɴ ? ɴ.to_s.downcase.to_sym : nil
155
171
  end
172
+ alias ɴ name
156
173
 
157
174
  # Constructor of units provides support for one additional named argument:
158
175
  # :abbreviation, alias :short. (This is in addition to :name, alias :ɴ named
159
176
  # argument provided by NameMagic.) As a general rule, only named units unit
160
177
  # should be given abbreviations. In choosing unit names and abbreviations,
161
178
  # ambiguity with regard to standard prefixes and abbreviations thereof should
162
- # also be avoided.
179
+ # also be avoided. Another argument, :warns, Boolean, <em>true</em> by
180
+ # default, determines whether the method warns about name collisions with
181
+ # other methods defined where the SY::ExpressibleInUnits mixin is included.
163
182
  #
164
- def initialize( short: nil, **nn )
183
+ def initialize( short: nil, warns: true, **nn )
165
184
  @abbreviation = short.to_sym if short
185
+ @warns = warns # does this unit care about blatant name collisions?
166
186
 
167
187
  # FIXME: Here, we would have to watch out for :amount being set
168
188
  # if it is a number, amount is in standard units
@@ -170,7 +190,7 @@ module SY::Unit
170
190
  # it estableshes a relationship between this and that quantity. It means that
171
191
  # the unit amount automatically becomes ... one ... and such relationship can
172
192
  # only be established for standard quantity
173
- super( **nn )
193
+ super nn
174
194
  end
175
195
 
176
196
  # Addition: Unit is converted to a magnitude before the operation.
@@ -213,7 +233,7 @@ module SY::Unit
213
233
  # Reframing: Unit is converted to a magnitude before reframing.
214
234
  #
215
235
  def reframe other_quantity
216
- to_magnitude.reframe( other_quantity )
236
+ to_magnnitude.reframe( other_quantity )
217
237
  end
218
238
 
219
239
  # Unit as string.
data/lib/sy/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module SY
2
- VERSION = "2.0.4"
2
+ VERSION = "2.0.5"
3
3
  DEBUG = false # debug mode switch - sometimes there are lines like
4
4
  # puts "something" if SY::DEBUG
5
5
  end
data/lib/sy.rb CHANGED
@@ -62,22 +62,17 @@ module SY
62
62
  # Let SY::Amount be a standard dimensionless quantity:
63
63
  Amount = Quantity.standard of: Dimension.zero
64
64
 
65
- # Convenience constructor of amounts:
66
- def self.Amount number
67
- SY::Amount.relative.magnitude number
68
- end
69
-
70
- # AVOGADRO_CONSTANT (Nᴀ) is a certain well-known amount of things:
71
- Nᴀ = AVOGADRO_CONSTANT = SY.Amount 6.02214e23
72
-
73
65
  # Let SY::UNIT be a standard unit of SY::Amount. Note that the upcase name
74
66
  # of the constant "UNIT" implies, via YSupport's NameMagic mixin, that the
75
67
  # name of the object becomes :unit and that it is possible to use syntax
76
68
  # such as 42.unit to create magnitudes of SY::Amount.
77
69
  UNIT = Unit.standard of: Amount
78
70
 
71
+ # AVOGADRO_CONSTANT (Nᴀ) is a certain well-known amount of things:
72
+ Nᴀ = AVOGADRO_CONSTANT = 6.02214e23
73
+
79
74
  # Let SY::MoleAmount be another dimensionless quantity:
80
- MoleAmount = Quantity.dimensionless
75
+ MoleAmount = Quantity.dimensionless # TODO: coerces: Amount
81
76
 
82
77
  # And let SY::MOLE be its standard unit, related to SY::Amount via Nᴀ:
83
78
  MOLE = Unit.standard of: MoleAmount, short: "mol", amount: Nᴀ.unit
@@ -138,13 +133,24 @@ module SY
138
133
  # Celsius temperature is a little bit peculiar in that it has offset of
139
134
  # 273.15.K with respect to Kelvin temperature, and I am not sure whether
140
135
  # at this moment SY is handling this right. But nevertheless:
141
- CelsiusTemperature = Quantity.of :Θ
136
+ CelsiusTemperature = Quantity.of :Θ # coerces_to: Temperature
137
+
138
+ CELSIUS_MEASURE = SY::Measure.simple_offset( TRIPLE_POINT_OF_WATER.in( :K ) )
142
139
 
143
140
  # Degree celsius is SY::CELSIUS
144
- CELSIUS = Unit.standard of: CelsiusTemperature, short: '°C', measure: SY::Measure.simple_offset( TRIPLE_POINT_OF_WATER.in( :K ) )
141
+ CELSIUS = Unit.standard( of: CelsiusTemperature,
142
+ short: '°C', measure: CELSIUS_MEASURE )
145
143
 
146
144
  class << CelsiusTemperature
147
145
  # FIXME: Patch CelsiusTemperature to make it work with SY::Temperature
146
+ # 1.°C + 1.K #=> 2.°C
147
+ # 1.°C - 1.°C #=> 0.K (unambiguous)
148
+ # 1.°C + 1.°C #=> QuantityError (ambiguous)
149
+ # 1.K +- 1.°C #=> QuantityError (ambiguous)
150
+ # 1.°C +- 1.K #=> 2.°C
151
+ # 1.mm.°C⁻¹ #=> 1.mm.K⁻¹ etc.
152
+ # 1.mm.°C #=> 1.mm.K etc.
153
+ # 1.mm */ 1.°C #=> QuantityError (ambiguous)
148
154
  end
149
155
 
150
156
  # alias :°C :celsius # with U+00B0 DEGREE SIGN
@@ -182,7 +188,7 @@ module SY
182
188
  Volume = Length ** 3
183
189
 
184
190
  # SY::LitreVolume is another quantity of the same dimension as SY::Volume:
185
- LitreVolume = Quantity.of Volume.dimension
191
+ LitreVolume = Quantity.of Volume.dimension # TODO: coerces_to: Volume
186
192
 
187
193
  # SY::LITRE is the standard unit of SY::LitreVolume:
188
194
  LITRE = Unit.standard of: LitreVolume, short: "l", amount: 1.dm³
data/test/sy_test.rb CHANGED
@@ -1,5 +1,5 @@
1
- #encoding: utf-8
2
1
  #! /usr/bin/ruby
2
+ # -*- coding: utf-8 -*-
3
3
 
4
4
  # **************************************************************************
5
5
  # THIS IS SPEC-STYLE TEST FILE FOR SY PHYSICAL UNITS LIBRARY
@@ -169,12 +169,15 @@ describe SY::Quantity, SY::Magnitude do
169
169
  1.inch.( @inch_length ).must_equal 1.inch
170
170
  1.inch.( SY::Length ).must_equal 2.54.cm
171
171
  @inch_length.magnitude( 1 ).to_s.must_equal "1.”"
172
- 1.inch.in( :mm ).must_equal 25.4
172
+ 1.inch.in( :mm ).must_be_within_epsilon 25.4
173
+ assert_equal SY::Unit.instance( :SECOND ), SY::Unit.instance( :second )
173
174
  end
174
175
  end
175
176
 
176
177
  describe "expected behavior" do
177
178
  it "should" do
179
+ assert_equal SY::Unit.instance( :SECOND ), SY::Unit.instance( :second )
180
+
178
181
  # Length quantity and typical units
179
182
  SY::METRE.must_be_kind_of SY::Unit
180
183
  SY::METRE.absolute?.must_equal true
@@ -289,7 +292,7 @@ describe SY::Quantity, SY::Magnitude do
289
292
  1.s⁻¹.must_equal 1.s ** -1
290
293
  q1 = ( 1.s⁻¹ ).quantity
291
294
  q1.composition.to_hash.must_equal( { SY::Time => -1 } )
292
-
295
+
293
296
  q2 = ( 1 / 1.s ).quantity
294
297
  q2.composition.to_hash.must_equal( { SY::Time => -1 } )
295
298
 
@@ -311,8 +314,8 @@ describe SY::Quantity, SY::Magnitude do
311
314
  end.must_include :M
312
315
  SY::Unit.instance_names.must_include :mole
313
316
  # Avogadro's number is defined directly in SY
314
- 1.mol.quantity.object_id.must_equal SY::Nᴀ.( SY::MoleAmount ).quantity.object_id
315
- SY::Nᴀ.( SY::MoleAmount ).must_equal 1.mol
317
+ 1.mol.quantity.object_id.must_equal SY::Nᴀ.unit.( SY::MoleAmount ).quantity.object_id
318
+ SY::Nᴀ.unit.( SY::MoleAmount ).must_equal 1.mol
316
319
  0.7.mol.l⁻¹.amount.must_equal 0.7
317
320
  1.M.must_equal 1.mol.l⁻¹.( SY::Molarity )
318
321
  # (if #reframe conversion method is not used, different quantities
@@ -345,16 +348,20 @@ describe SY::Quantity, SY::Magnitude do
345
348
  1e-23.J.K⁻¹.must_equal 1.0e-20.mJ.K⁻¹
346
349
 
347
350
 
351
+
348
352
  # pascal
349
353
  ( 1.N / 1.m ** 2 ).( SY::Pressure ).must_be_within_epsilon 1.Pa, 1e-9
350
354
 
351
355
  # watt
352
356
  ( 1.V * 1.A ).( SY::Power ).must_be_within_epsilon 1.W, 1e-9
353
357
 
358
+
354
359
  # pretty representation
355
- ( 1.m / 3.s ).to_s.must_equal( "0.333.m.s⁻¹" )
360
+ assert_equal SY::Unit.instance( :SECOND ), SY::Unit.instance( :second )
361
+ ( 1.m / 3.s ).to_s.must_equal( "0.333.m.s⁻¹" ) # FIXME: Discovered a problem here, uncomment the line below
362
+ # assert_equal SY::Unit.instance( :SECOND ), SY::Unit.instance( :second )
356
363
  ( 1.m / 7.01e7.s ).to_s.must_equal( "1.43e-08.m.s⁻¹" )
357
-
364
+
358
365
  assert_equal 1.m, 1.s * 1.m.s⁻¹
359
366
  assert_equal 1.µM.s⁻¹, 1.µM / 1.s
360
367
  assert_equal 1.m.s⁻¹, 1.m.s( -1 )
@@ -365,7 +372,7 @@ describe SY::Quantity, SY::Magnitude do
365
372
  assert_equal SY::Amount( 1 ), 1.µM / ( 1.µM + 0.µM )
366
373
  assert_equal 1.µM, 1.µM * 1.µM / ( 1.µM + 0.µM )
367
374
  assert_in_epsilon 1.µM, 1.µmol / 1.dm( 3 ).( SY::LitreVolume )
368
-
375
+
369
376
  assert_equal SY::Molarity.relative, 1.mol.l⁻¹.quantity
370
377
 
371
378
  assert_equal 1 / SY::Time, 1 / SY::Time
@@ -380,6 +387,11 @@ describe SY::Quantity, SY::Magnitude do
380
387
  assert_equal Matrix[[2.m, 3.m], [4.m, 5.m]],
381
388
  Matrix[[1.m, 2.m], [3.m, 4.m]] + Matrix[[1.m, 1.m], [1.m, 1.m]]
382
389
  assert_equal Matrix[[5.µM]], Matrix[[1.µM]] + Matrix[[2.µM.s⁻¹]] * Matrix[[2.s]]
390
+ XOXO = SY::Unit.of SY::Volume, amount: 1.l
391
+ assert_equal 1.l.( SY::Volume ), 1.xoxo.( SY::Volume )
392
+ assert_equal SY::TRIPLE_POINT_OF_WATER, 0.°C.( SY::Temperature )
393
+ assert_equal 273.15, 0.°C.in( :K )
394
+ # assert_equal SY::TRIPLE_POINT_OF_WATER, 0.°C # so far unfinished coercion behavior
383
395
  end
384
396
  end
385
397
  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.0.4
4
+ version: 2.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - boris
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-05-19 00:00:00.000000000 Z
11
+ date: 2013-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport