phys-units 0.9.3 → 0.9.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/README.md +84 -19
- data/lib/phys/units.rb +1 -0
- data/lib/phys/units/mixin.rb +3 -16
- data/lib/phys/units/parse.rb +1 -1
- data/lib/phys/units/parse.y +1 -1
- data/lib/phys/units/quantity.rb +112 -36
- data/lib/phys/units/unit.rb +77 -74
- data/lib/phys/units/unit_class.rb +32 -15
- data/lib/phys/units/units_mixin.rb +80 -0
- data/lib/phys/units/version.rb +1 -1
- data/spec/unit_spec.rb +3 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0ec7810800a733cda3aa7f753bf10d11b76891d
|
4
|
+
data.tar.gz: b2c93b618d876183ea89ebfab9e6f353a6160746
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0b1ea5529d3017813abe2c056b8eda47db00f47dd3cf0405fd0551182f551bdd95493352ea0ff8ecce1091e5269a593411c09d1caa705514d9c39520e8d54b5
|
7
|
+
data.tar.gz: 7d4bdf5a200c37d8d9cd7b0416bbaa7812a988905b358ea93e88dd635f056226305a6c57bbae0bfe27c48ef7ed9080a64ca91a28fcabc9b66675b4ab082443fd
|
data/README.md
CHANGED
@@ -1,38 +1,63 @@
|
|
1
1
|
# Phys-Units
|
2
2
|
|
3
|
-
GNU Units-compatible library for Ruby.
|
3
|
+
[GNU Units](http://www.gnu.org/software/units/)-compatible library for Ruby.
|
4
4
|
Former name is [Quanty](http://narray.rubyforge.org/quanty/quanty-en.html),
|
5
5
|
the first Ruby units library released in 2001.
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
* [GitHub](https://github.com/masa16/phys-units)
|
8
|
+
* [RubyGems](https://rubygems.org/gems/phys-units)
|
9
|
+
* [Class Documentation](http://rubydoc.info/gems/phys-units/frames/)
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Install from gem as:
|
14
|
+
|
15
|
+
$ gem install phys-units
|
16
|
+
|
17
|
+
Or install from source tree:
|
18
|
+
|
19
|
+
$ ruby setup.rb
|
20
|
+
|
21
|
+
## Overview
|
22
|
+
|
23
|
+
### Phys::Quantity
|
24
|
+
is the primary class of Phys-Units library, intended to be manipulated by users.
|
25
|
+
This class represents Physical Quantities with a Unit of measurement.
|
26
|
+
It contains *Value* and *Unit*.
|
10
27
|
|
11
28
|
* *Value*
|
12
29
|
must be a class instance having arithmetic methods,
|
13
30
|
but it is not necessary to be a Numeric.
|
14
31
|
This is a duck typing way.
|
32
|
+
|
33
|
+
Phys::Quantity[2.5,"miles"].value #=> 2.5
|
34
|
+
|
15
35
|
* *Unit*
|
16
|
-
is an instance of Phys::Unit class
|
17
|
-
obtained by parsing *expr* string.
|
36
|
+
is an instance of Phys::Unit class obtained by parsing *expr* string.
|
18
37
|
|
19
|
-
|
20
|
-
for more details.
|
38
|
+
Phys::Quantity[2.5,"miles"].unit #=> #<Phys::Unit 1609.344,{"m"=>1},@expr="5280 ft">
|
21
39
|
|
22
|
-
|
40
|
+
### Phys::Unit
|
41
|
+
is a class to represent Physical Units of measurement.
|
42
|
+
This class is used in the Phys::Quantity for calculations with Units,
|
43
|
+
and users do not always need to know its mechanism.
|
44
|
+
It has *Factor* and *Dimension*:
|
23
45
|
|
24
|
-
|
46
|
+
* *Factor* of the unit is a scale factor relative to its base unit.
|
25
47
|
|
26
|
-
|
48
|
+
Phys::Unit["km"].factor #=> 1000
|
27
49
|
|
28
|
-
|
50
|
+
* *Dimension* of the unit
|
51
|
+
is a hash table containing base units and dimensions as key-value pairs.
|
29
52
|
|
30
|
-
|
53
|
+
Phys::Unit["N"].dimension #=> {"kg"=>1, "m"=>1, "s"=>-2}
|
31
54
|
|
32
|
-
|
55
|
+
### Examples
|
33
56
|
|
34
|
-
require
|
57
|
+
require "phys/units"
|
35
58
|
Q = Phys::Quantity
|
59
|
+
U = Phys::Unit
|
60
|
+
|
36
61
|
Q[1.23,'km'] + Q[4.56,'m'] #=> Phys::Quantity[1.23456,'km']
|
37
62
|
Q[123,'mile'] / Q[2,'hr'] #=> Phys::Quantity[61,'mile/hr']
|
38
63
|
Q[61,'miles/hr'].want('m/s') #=> Phys::Quantity[27.26944,'m/s']
|
@@ -41,17 +66,32 @@ Or install from source tree:
|
|
41
66
|
Q[20,'tempC'].want('tempF') #=> Phys::Quantity[68,'tempF']
|
42
67
|
Math.cos(Q[60,'degree'].to_f) #=> 0.5
|
43
68
|
|
69
|
+
U["m/s"] === Q[1,'miles/hr'] #=> true
|
70
|
+
|
71
|
+
case Q[1,"miles/hr"]
|
72
|
+
when U["LENGTH"]
|
73
|
+
puts "length"
|
74
|
+
when U["TIME"]
|
75
|
+
puts "time"
|
76
|
+
when U["VELOCITY"]
|
77
|
+
puts "velocity"
|
78
|
+
else
|
79
|
+
puts "other"
|
80
|
+
end #=> "velocity"
|
81
|
+
|
44
82
|
## Features
|
45
83
|
|
46
|
-
Phys-Units library is
|
84
|
+
Phys-Units library is differentiated from many other units libraries for Ruby,
|
47
85
|
by the following features:
|
48
86
|
|
49
87
|
* Compatible with GNU Units except nonlinear units.
|
50
88
|
* Provides 2331 units, 85 prefixes, including UTF-8 unit names.
|
51
|
-
* Defines Units by reading GNU Units text data
|
89
|
+
* Defines Units by reading GNU Units text data
|
90
|
+
(see [load_units.rb](https://github.com/masa16/phys-units/blob/master/lib/phys/units/load_units.rb)),
|
52
91
|
unlike other libraries which define Units in Ruby code.
|
53
|
-
*
|
54
|
-
|
92
|
+
* Provides orthodox design of class interface.
|
93
|
+
* No addition or modification to Ruby standard classes in standard usage,
|
94
|
+
to avoid conflicts with other libraries.
|
55
95
|
* Calculation of values is through Ruby Numeric arithmetic methods.
|
56
96
|
Phys-Units does not care it.
|
57
97
|
* Conversion factors are internally held in Rational form even
|
@@ -59,6 +99,31 @@ by the following features:
|
|
59
99
|
* PI number has a dimension.
|
60
100
|
* Japanese Units are available by require 'phys/units/jp'.
|
61
101
|
|
102
|
+
## Appendix Feature
|
103
|
+
|
104
|
+
Mix-in feature provides simple calculator of units.
|
105
|
+
Caution: The use of Mix-in may cause conflicts with other library.
|
106
|
+
|
107
|
+
$ irb -rphys/units/mixin
|
108
|
+
|
109
|
+
irb> (2.5.miles/hr).want m/s
|
110
|
+
=> Phys::Quantity[1.1176,"m/s"]
|
111
|
+
|
112
|
+
irb> 23.tempC.want tempF
|
113
|
+
=> Phys::Quantity[73.4,"tempF"]
|
114
|
+
|
115
|
+
irb> print_units LENGTH
|
116
|
+
m !
|
117
|
+
meter m
|
118
|
+
LENGTH meter
|
119
|
+
:
|
120
|
+
|
121
|
+
irb> print_units ENERGY
|
122
|
+
joule N m
|
123
|
+
J joule
|
124
|
+
prout 185.5 keV
|
125
|
+
:
|
126
|
+
|
62
127
|
## Platforms tested
|
63
128
|
|
64
129
|
* ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-linux]
|
data/lib/phys/units.rb
CHANGED
data/lib/phys/units/mixin.rb
CHANGED
@@ -1,18 +1,5 @@
|
|
1
1
|
require "phys/units"
|
2
2
|
|
3
|
-
#
|
4
|
-
|
5
|
-
|
6
|
-
#
|
7
|
-
# However, this kind of global change will cause unexpected problems.
|
8
|
-
|
9
|
-
class Numeric
|
10
|
-
alias method_missing_orig method_missing
|
11
|
-
def method_missing(method, *args, &block)
|
12
|
-
if unit=Phys::Unit.find_unit(method.to_s)
|
13
|
-
Phys::Quantity.new(self,nil,unit)
|
14
|
-
else
|
15
|
-
method_missing_orig(method,*args, &block)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
3
|
+
# @visibility private
|
4
|
+
class Numeric; include Phys::UnitsNumericMixin; end
|
5
|
+
include Phys::UnitsMixin
|
data/lib/phys/units/parse.rb
CHANGED
data/lib/phys/units/parse.y
CHANGED
data/lib/phys/units/quantity.rb
CHANGED
@@ -14,19 +14,27 @@ module Phys
|
|
14
14
|
# Quantity.new(*a)
|
15
15
|
#end
|
16
16
|
|
17
|
-
# Phys::Quantity is
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
17
|
+
# Phys::Quantity is the primary class of Phys-Units library,
|
18
|
+
# intended to be manipulated by users.
|
19
|
+
# This class represents Physical Quantities with a Unit of measurement.
|
20
|
+
# It contains *Value* and *Unit*.
|
21
|
+
# * *Value* of the quantity
|
22
|
+
# must be an instance having arithmetic methods,
|
22
23
|
# but it is not necessary to be a Numeric.
|
23
24
|
# This is a duck typing way.
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
|
25
|
+
# Phys::Quantity[2.5,"miles"].value #=> 2.5
|
26
|
+
# Phys::Quantity[NArray.float(5).indgen,"miles"].want("m").value
|
27
|
+
# #=> NArray.float(5):
|
28
|
+
# [ 0.0, 1609.34, 3218.69, 4828.03, 6437.38 ]
|
29
|
+
# * *Unit*
|
30
|
+
# is an instance of Phys::Unit class obtained by parsing *expr* string.
|
31
|
+
# see document of Phys::Unit.
|
32
|
+
# Phys::Quantity[2.5,"miles"].unit #=> #<Phys::Unit 1609.344,{"m"=>1},@expr="5280 ft">
|
33
|
+
#
|
34
|
+
# @example
|
28
35
|
# require 'phys/units'
|
29
|
-
# Q=Phys::Quantity
|
36
|
+
# Q = Phys::Quantity
|
37
|
+
#
|
30
38
|
# Q[1.23,'km'] + Q[4.56,'m'] #=> Phys::Quantity[1.23456,'km']
|
31
39
|
# Q[123,'mile'] / Q[2,'hr'] #=> Phys::Quantity[61,'mile/hr']
|
32
40
|
# Q[61,'miles/hr'].want('m/s') #=> Phys::Quantity[27.26944,'m/s']
|
@@ -34,43 +42,71 @@ module Phys
|
|
34
42
|
# Q[70,'tempF'] + Q[10,'tempC'] #=> Phys::Quantity[88,'tempF']
|
35
43
|
# Q[20,'tempC'].want('tempF') #=> Phys::Quantity[68,'tempF']
|
36
44
|
# Math.cos(Q[60,'degree'].to_f) #=> 0.5
|
45
|
+
#
|
46
|
+
# @see Unit
|
47
|
+
#
|
37
48
|
class Quantity
|
38
49
|
|
50
|
+
@@verbose_inspect = false
|
51
|
+
|
39
52
|
class << self
|
40
53
|
# Alias to Phys::Quantity.new.
|
41
|
-
#
|
42
|
-
#
|
43
|
-
# @
|
44
|
-
#
|
54
|
+
# @param [Object] value Value of quantity.
|
55
|
+
# @param [String,Symbol] expr Unit string to be parsed later.
|
56
|
+
# @overload initialize(value,unit)
|
57
|
+
# @param [Object] value Value of quantity.
|
58
|
+
# @param [Phys::Unit] unit This unit is copyed if exists.
|
59
|
+
# @overload initialize(value)
|
60
|
+
# @param [Object] value Value of dimensionless quantity.
|
45
61
|
# @return [Phys::Quantity]
|
46
|
-
# @raise
|
62
|
+
# @raise [TypeError] if invalid arg types.
|
63
|
+
# @raise [Phys::UnitError] if unit conversion is failed.
|
47
64
|
def [](value,expr=nil)
|
48
65
|
self.new(value,expr)
|
49
66
|
end
|
50
67
|
end
|
51
68
|
|
52
69
|
# Initialize a new quantity.
|
53
|
-
# @
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
# @
|
58
|
-
#
|
70
|
+
# @overload initialize(value,expr,unit=nil)
|
71
|
+
# @param [Object] value Value of quantity.
|
72
|
+
# @param [String,Symbol] expr Unit string to be parsed later.
|
73
|
+
# @param [Phys::Unit] unit This unit is copyed if exists.
|
74
|
+
# @overload initialize(value,unit)
|
75
|
+
# @param [Object] value Value of quantity.
|
76
|
+
# @param [Phys::Unit] unit This unit is copyed if exists.
|
77
|
+
# @overload initialize(value)
|
78
|
+
# @param [Object] value Value of dimensionless quantity.
|
79
|
+
# @raise [TypeError] if invalid arg types.
|
80
|
+
# @raise [Phys::UnitError] if unit conversion is failed.
|
59
81
|
#
|
60
82
|
def initialize(value,expr=nil,unit=nil)
|
61
83
|
@value = value
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
84
|
+
case expr
|
85
|
+
when String, Symbol
|
86
|
+
@expr = expr.to_s.strip
|
87
|
+
@expr = nil if @expr==''
|
88
|
+
@unit = unit
|
89
|
+
when NilClass
|
90
|
+
@expr = nil
|
91
|
+
@unit = unit
|
92
|
+
when Unit
|
93
|
+
raise "Wrong # of argument" if unit
|
94
|
+
@expr = nil
|
95
|
+
@unit = expr
|
96
|
+
else
|
97
|
+
raise ArgumentError,"Second argument is invalid: #{expr.inspect}"
|
98
|
+
end
|
99
|
+
case @unit
|
100
|
+
when NilClass
|
66
101
|
@unit = Unit.parse(@expr||1)
|
67
|
-
|
68
|
-
|
102
|
+
when Unit
|
103
|
+
else
|
104
|
+
raise ArgumentError, "Third argument is invalid: #{@unit.inspect}"
|
69
105
|
end
|
70
106
|
end
|
71
107
|
|
72
108
|
# Value of the quantity.
|
73
|
-
# Instance of classes with same arithmetic methods as
|
109
|
+
# Instance of classes with same arithmetic methods as Numeric.
|
74
110
|
# @return [Object]
|
75
111
|
attr_reader :value
|
76
112
|
alias val value
|
@@ -84,13 +120,28 @@ module Phys
|
|
84
120
|
attr_reader :unit
|
85
121
|
|
86
122
|
# Conversion to a quantity in another unit.
|
87
|
-
# @param [String]
|
88
|
-
# @return [Phys::Quantity] quantity in the unit of +
|
123
|
+
# @param [String,Symbol,Unit,Quantity] unit unit expression.
|
124
|
+
# @return [Phys::Quantity] quantity in the unit of +unit+.
|
89
125
|
# @raise [Phys::UnitError] if unit conversion is failed.
|
90
126
|
#
|
91
|
-
def want(
|
92
|
-
unit
|
93
|
-
|
127
|
+
def want(unit=nil)
|
128
|
+
case unit
|
129
|
+
when Unit
|
130
|
+
expr = unit.expr
|
131
|
+
when Quantity
|
132
|
+
expr = unit.expr
|
133
|
+
unit = unit.unit
|
134
|
+
when String,Symbol
|
135
|
+
expr = unit
|
136
|
+
unit = Unit.parse(expr)
|
137
|
+
when Numeric
|
138
|
+
unit = Unit.cast(unit)
|
139
|
+
when NilClass
|
140
|
+
unit = Unit.cast(1)
|
141
|
+
else
|
142
|
+
raise TypeError, "invalid argument: #{unit.inspect}"
|
143
|
+
end
|
144
|
+
val = unit.convert(self)
|
94
145
|
self.class.new( val, expr, unit )
|
95
146
|
end
|
96
147
|
alias convert want
|
@@ -204,7 +255,7 @@ module Phys
|
|
204
255
|
end
|
205
256
|
end
|
206
257
|
|
207
|
-
# Comparison. Returns +true+ if +self+ is
|
258
|
+
# Comparison. Returns +true+ if +self+ is greater-than or equal-to +other+.
|
208
259
|
# Before the comparison, it converts +other+ to the unit of +self+.
|
209
260
|
# @param [Phys::Quantity] other
|
210
261
|
# @return [Boolean]
|
@@ -260,7 +311,7 @@ module Phys
|
|
260
311
|
def **(n)
|
261
312
|
if @expr.nil?
|
262
313
|
expr = nil
|
263
|
-
elsif /^[A-Za-z_]
|
314
|
+
elsif /^[A-Za-z_]+$/o =~ @expr
|
264
315
|
expr = @expr+'^'+n.to_s
|
265
316
|
else
|
266
317
|
expr = '('+@expr+')^'+n.to_s+''
|
@@ -496,7 +547,32 @@ module Phys
|
|
496
547
|
else
|
497
548
|
expr = ""
|
498
549
|
end
|
499
|
-
|
550
|
+
if @@verbose_inspect
|
551
|
+
sufx = " "+@unit.inspect
|
552
|
+
else
|
553
|
+
sufx = ""
|
554
|
+
end
|
555
|
+
self.class.to_s+"["+Unit::Utils.num_inspect(@value)+expr+"]"+sufx
|
556
|
+
end
|
557
|
+
|
558
|
+
# Comformability of quantity. Returns true if unit conversion between +self+ and +x+ is possible.
|
559
|
+
# @param [Object] x other object (Unit or Quantity or Numeric or something else)
|
560
|
+
# @return [Boolean]
|
561
|
+
def ===(x)
|
562
|
+
case x
|
563
|
+
when Unit
|
564
|
+
unit === x
|
565
|
+
when Quantity
|
566
|
+
unit === x.unit
|
567
|
+
when Numeric
|
568
|
+
unit.dimensionless?
|
569
|
+
else
|
570
|
+
false
|
571
|
+
end
|
500
572
|
end
|
573
|
+
alias conformable? ===
|
574
|
+
alias compatible? ===
|
575
|
+
alias conversion_allowed? ===
|
576
|
+
|
501
577
|
end
|
502
578
|
end
|
data/lib/phys/units/unit.rb
CHANGED
@@ -9,22 +9,24 @@
|
|
9
9
|
|
10
10
|
module Phys
|
11
11
|
|
12
|
-
# Phys::Unit is a class to represent Physical
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# * *
|
17
|
-
#
|
18
|
-
#
|
12
|
+
# Phys::Unit is a class to represent Physical Units of measurement.
|
13
|
+
# This class is used in the Phys::Quantity for calculations with Units,
|
14
|
+
# and users do not always need to know its mechanism.
|
15
|
+
# It has *Factor* and *Dimension*:
|
16
|
+
# * *Factor* of the unit is a scale factor relative to its base unit.
|
17
|
+
# Phys::Unit["km"].factor #=> 1000
|
18
|
+
# * *Dimension* of the unit
|
19
|
+
# is a hash table containing base units and dimensions as key-value pairs.
|
19
20
|
# Phys::Unit["N"].dimension #=> {"kg"=>1, "m"=>1, "s"=>-2}
|
20
|
-
|
21
|
+
# @example
|
21
22
|
# require "phys/units"
|
22
23
|
# Q = Phys::Quantity
|
23
24
|
# U = Phys::Unit
|
24
25
|
#
|
25
|
-
# U["miles"] / U["hr"]
|
26
|
-
# U["hr"] + U["30 min"]
|
27
|
-
# U["(m/s)"]**2
|
26
|
+
# U["miles"] / U["hr"] #=> #<Phys::Unit 0.44704,{"m"=>1, "s"=>-1}>
|
27
|
+
# U["hr"] + U["30 min"] #=> #<Phys::Unit 5400,{"s"=>1}>
|
28
|
+
# U["(m/s)"]**2 #=> #<Phys::Unit 1,{"m"=>2, "s"=>-2}>
|
29
|
+
# U["m/s"] === Q[1,'miles/hr'] #=> true
|
28
30
|
#
|
29
31
|
# case Q[1,"miles/hr"]
|
30
32
|
# when U["m"]
|
@@ -36,6 +38,9 @@ module Phys
|
|
36
38
|
# else
|
37
39
|
# "other"
|
38
40
|
# end #=> "velocity"
|
41
|
+
#
|
42
|
+
# @see Quantity
|
43
|
+
#
|
39
44
|
class Unit
|
40
45
|
|
41
46
|
# @visibility private
|
@@ -50,7 +55,7 @@ module Phys
|
|
50
55
|
|
51
56
|
# Initialize a new unit.
|
52
57
|
# @overload initialize(factor,dimension=nil)
|
53
|
-
# @param [Numeric] factor Unit
|
58
|
+
# @param [Numeric] factor Unit scale factor.
|
54
59
|
# @param [Hash] dimension Dimension hash.
|
55
60
|
# @overload initialize(expr,name=nil)
|
56
61
|
# @param [String] expr Unit string to be parsed later.
|
@@ -58,23 +63,23 @@ module Phys
|
|
58
63
|
# @overload initialize(unit,name=nil)
|
59
64
|
# @param [Phys::Unit] unit Copy contents from the argument.
|
60
65
|
# @param [String] name Name of this unit.
|
61
|
-
# @raise [TypeError] if
|
66
|
+
# @raise [TypeError] if invalid arg types.
|
62
67
|
#
|
63
|
-
def initialize(
|
64
|
-
case
|
68
|
+
def initialize(a1,a2=nil)
|
69
|
+
case a1
|
65
70
|
when Numeric
|
66
|
-
|
67
|
-
@factor =
|
68
|
-
alloc_dim(
|
71
|
+
a1 = Rational(a1) if Integer===a1
|
72
|
+
@factor = a1
|
73
|
+
alloc_dim(a2)
|
69
74
|
when Phys::Unit
|
70
|
-
@factor =
|
71
|
-
alloc_dim
|
72
|
-
@name =
|
75
|
+
@factor = a1.factor
|
76
|
+
alloc_dim a1.dim
|
77
|
+
@name = a2.strip if a2
|
73
78
|
when String
|
74
|
-
@expr =
|
75
|
-
@name =
|
79
|
+
@expr = a1.strip
|
80
|
+
@name = a2.strip if a2
|
76
81
|
else
|
77
|
-
raise TypeError,"
|
82
|
+
raise TypeError,"Invalid argument: #{a1.inspect}"
|
78
83
|
end
|
79
84
|
end
|
80
85
|
|
@@ -97,16 +102,21 @@ module Phys
|
|
97
102
|
end
|
98
103
|
alias dim dimension
|
99
104
|
|
100
|
-
#
|
105
|
+
# Scale factor excluding the dimension-value.
|
101
106
|
# @return [Numeric]
|
107
|
+
# @example
|
108
|
+
# Phys::Unit["deg"].dimension #=> {"pi"=>1, "radian"=>1}
|
109
|
+
# Phys::Unit["deg"].factor #=> (1/180)
|
110
|
+
# Phys::Unit["deg"].conversion_factor #=> 0.017453292519943295
|
111
|
+
# @see #conversion_factor
|
102
112
|
def factor
|
103
113
|
use_dimension
|
104
114
|
@factor
|
105
115
|
end
|
106
116
|
|
107
|
-
# Dimension value.
|
108
|
-
# otherwise returns one. see BaseUnit.
|
117
|
+
# Dimension value. Always returns 1 unless BaseUnit.
|
109
118
|
# @return [Numeric]
|
119
|
+
# @see BaseUnit#dimension_value
|
110
120
|
def dimension_value
|
111
121
|
1
|
112
122
|
end
|
@@ -154,9 +164,12 @@ module Phys
|
|
154
164
|
|
155
165
|
# Inspect string.
|
156
166
|
# @return [String]
|
167
|
+
# @example
|
168
|
+
# Phys::Unit["N"].inspect #=> '#<Phys::Unit 1,{"kg"=>1, "m"=>1, "s"=>-2},@expr="newton">'
|
157
169
|
def inspect
|
170
|
+
use_dimension
|
158
171
|
a = [Utils.num_inspect(@factor), @dim.inspect]
|
159
|
-
|
172
|
+
a << "@name="+@name.inspect if @name
|
160
173
|
a << "@expr="+@expr.inspect if @expr
|
161
174
|
a << "@offset="+@offset.inspect if @offset
|
162
175
|
a << "@dimensionless=true" if @dimensionless
|
@@ -167,8 +180,10 @@ module Phys
|
|
167
180
|
"#<#{self.class} #{s}>"
|
168
181
|
end
|
169
182
|
|
170
|
-
# Make
|
183
|
+
# Make a string of this unit expressed in base units.
|
171
184
|
# @return [String]
|
185
|
+
# @example
|
186
|
+
# Phys::Unit["psi"].string_form #=> "(8896443230521/129032)*1e-04 kg m^-1 s^-2"
|
172
187
|
def unit_string
|
173
188
|
use_dimension
|
174
189
|
a = []
|
@@ -184,8 +199,13 @@ module Phys
|
|
184
199
|
end
|
185
200
|
alias string_form unit_string
|
186
201
|
|
187
|
-
# Conversion Factor to base unit.
|
202
|
+
# Conversion Factor to base unit, including dimension-value.
|
188
203
|
# @return [Numeric]
|
204
|
+
# @example
|
205
|
+
# Phys::Unit["deg"].dimension #=> {"pi"=>1, "radian"=>1}
|
206
|
+
# Phys::Unit["deg"].factor #=> (1/180)
|
207
|
+
# Phys::Unit["deg"].conversion_factor #=> 0.017453292519943295
|
208
|
+
# @see #factor
|
189
209
|
def conversion_factor
|
190
210
|
use_dimension
|
191
211
|
f = @factor
|
@@ -202,7 +222,7 @@ module Phys
|
|
202
222
|
|
203
223
|
# Returns true if scalar unit.
|
204
224
|
# *Scalar* means the unit does not have any dimension
|
205
|
-
# including dimensionless-
|
225
|
+
# including dimensionless-units, and its factor is one.
|
206
226
|
# @return [Boolean]
|
207
227
|
def scalar?
|
208
228
|
use_dimension
|
@@ -248,10 +268,10 @@ module Phys
|
|
248
268
|
end
|
249
269
|
end
|
250
270
|
|
251
|
-
# Comformability of units. Returns true if unit conversion is
|
252
|
-
# @param [Object] x other object (
|
271
|
+
# Comformability of units. Returns true if unit conversion between +self+ and +x+ is possible.
|
272
|
+
# @param [Object] x other object (Unit or Quantity or Numeric or something else)
|
253
273
|
# @return [Boolean]
|
254
|
-
def
|
274
|
+
def ===(x)
|
255
275
|
case x
|
256
276
|
when Unit
|
257
277
|
dimensionless_deleted == x.dimensionless_deleted
|
@@ -263,9 +283,9 @@ module Phys
|
|
263
283
|
false
|
264
284
|
end
|
265
285
|
end
|
266
|
-
alias
|
267
|
-
alias compatible?
|
268
|
-
alias conversion_allowed?
|
286
|
+
alias conformable? ===
|
287
|
+
alias compatible? ===
|
288
|
+
alias conversion_allowed? ===
|
269
289
|
|
270
290
|
# Convert a quantity to this unit.
|
271
291
|
# @param [Phys::Quantity] quantity to be converted.
|
@@ -314,7 +334,7 @@ module Phys
|
|
314
334
|
alias to_num to_numeric
|
315
335
|
|
316
336
|
|
317
|
-
# Returns Base Unit excluding dimensionless-
|
337
|
+
# Returns Base Unit excluding dimensionless-units.
|
318
338
|
# @return [Phys::Unit]
|
319
339
|
def base_unit
|
320
340
|
Unit.new(1,dimensionless_deleted)
|
@@ -367,7 +387,7 @@ module Phys
|
|
367
387
|
x.dup
|
368
388
|
end
|
369
389
|
else
|
370
|
-
raise "
|
390
|
+
raise "dimension not defined"
|
371
391
|
end
|
372
392
|
end
|
373
393
|
|
@@ -384,7 +404,7 @@ module Phys
|
|
384
404
|
end
|
385
405
|
dims
|
386
406
|
else
|
387
|
-
raise "
|
407
|
+
raise "dimension not defined"
|
388
408
|
end
|
389
409
|
end
|
390
410
|
|
@@ -465,29 +485,6 @@ module Phys
|
|
465
485
|
Unit.new(factor,dims)
|
466
486
|
end
|
467
487
|
|
468
|
-
# Rational division of units.
|
469
|
-
# Both units must be operable.
|
470
|
-
# @param [Phys::Unit, Numeric] x other unit
|
471
|
-
# @return [Phys::Unit]
|
472
|
-
# @raise [Phys::UnitError] if not operable.
|
473
|
-
def rdiv(x)
|
474
|
-
x = Unit.cast(x)
|
475
|
-
if scalar?
|
476
|
-
return x.inverse
|
477
|
-
elsif x.scalar?
|
478
|
-
return self
|
479
|
-
end
|
480
|
-
check_operable2(x)
|
481
|
-
dims = dimension_binop(x){|a,b| a-b}
|
482
|
-
factor = Rational(self.factor,x.factor)
|
483
|
-
Unit.new(factor,dims)
|
484
|
-
end
|
485
|
-
|
486
|
-
# @visibility private
|
487
|
-
def self.rdiv(x,y)
|
488
|
-
Unit.cast(x).rdiv(y)
|
489
|
-
end
|
490
|
-
|
491
488
|
# Inverse of units.
|
492
489
|
# This unit must be operable.
|
493
490
|
# @param [Phys::Unit, Numeric] unit
|
@@ -548,26 +545,32 @@ module Phys
|
|
548
545
|
end # Unit
|
549
546
|
|
550
547
|
|
551
|
-
# BaseUnit is a class to represent units defined by "!"
|
552
|
-
#
|
548
|
+
# BaseUnit is a class to represent units defined by "!"
|
549
|
+
# in the data form of GNU units.
|
550
|
+
# It includes SI units and dimensinless units such as radian.
|
553
551
|
class BaseUnit < Unit
|
554
552
|
|
555
553
|
def self.define(name,expr,dimval=nil)
|
556
|
-
|
557
|
-
|
554
|
+
if LIST[name]
|
555
|
+
warn "unit definition is overwritten: #{name}" if debug
|
556
|
+
end
|
557
|
+
LIST[name] = self.new(expr,name,dimval)
|
558
558
|
end
|
559
559
|
|
560
|
-
def initialize(name,
|
560
|
+
def initialize(expr,name,dimval=nil)
|
561
561
|
case name
|
562
562
|
when String
|
563
|
-
@name = name
|
563
|
+
@name = name.strip
|
564
564
|
@factor = 1
|
565
|
-
@dim = {name=>1}
|
565
|
+
@dim = {@name=>1}
|
566
566
|
@dim.default = 0
|
567
|
-
@
|
567
|
+
@expr = expr
|
568
|
+
if String===expr && /!dimensionless/ =~ expr
|
569
|
+
@dimensionless = true
|
570
|
+
end
|
568
571
|
@dimension_value = dimval || 1
|
569
572
|
else
|
570
|
-
raise ArgumentError
|
573
|
+
raise ArgumentError,"Second argument must be string: #{name}"
|
571
574
|
end
|
572
575
|
end
|
573
576
|
|
@@ -598,7 +601,7 @@ module Phys
|
|
598
601
|
|
599
602
|
|
600
603
|
# OffsetUnit is a class to represent units with offset value.
|
601
|
-
#
|
604
|
+
# Allows Farenheight/Celsius temperature.
|
602
605
|
class OffsetUnit < Unit
|
603
606
|
|
604
607
|
def self.define(name,unit,offset=nil)
|
@@ -623,7 +626,7 @@ module Phys
|
|
623
626
|
v = quantity.value * quantity.unit.conversion_factor
|
624
627
|
v = v / self.conversion_factor
|
625
628
|
else
|
626
|
-
raise UnitError,"not
|
629
|
+
raise UnitError,"not Quantity: #{quantity.inspect}"
|
627
630
|
end
|
628
631
|
end
|
629
632
|
|
@@ -18,12 +18,16 @@ module Phys
|
|
18
18
|
false
|
19
19
|
end
|
20
20
|
|
21
|
-
# Define
|
22
|
-
# @param [String] name Name of this unit.
|
21
|
+
# Define a new Unit. Expression is not parsed at the time of this method.
|
22
|
+
# @param [String,Symbol] name Name of this unit.
|
23
23
|
# @param [String] expr Expression.
|
24
24
|
def define(name,expr)
|
25
|
-
|
26
|
-
|
25
|
+
case name
|
26
|
+
when String
|
27
|
+
when Symbol
|
28
|
+
name = name.to_s
|
29
|
+
else
|
30
|
+
raise TypeError,"Unit name must be String or Symbol: #{name.inspect}"
|
27
31
|
end
|
28
32
|
if /^(.*)-$/ =~ name
|
29
33
|
name = $1
|
@@ -36,8 +40,7 @@ module Phys
|
|
36
40
|
warn "unit definition is overwritten: #{name}" if debug
|
37
41
|
end
|
38
42
|
if expr.kind_of?(String) && /^!/ =~ expr
|
39
|
-
|
40
|
-
LIST[name] = BaseUnit.new(name,dimless)
|
43
|
+
LIST[name] = BaseUnit.new(expr,name)
|
41
44
|
else
|
42
45
|
LIST[name] = self.new(expr,name)
|
43
46
|
end
|
@@ -45,10 +48,12 @@ module Phys
|
|
45
48
|
end
|
46
49
|
|
47
50
|
|
48
|
-
# Force argument to be Phys::Unit.
|
51
|
+
# Force the argument to be Phys::Unit.
|
52
|
+
# @param [Phys::Unit,Numeric]
|
49
53
|
# @return [Phys::Unit]
|
50
54
|
def cast(x)
|
51
|
-
|
55
|
+
case x
|
56
|
+
when Unit
|
52
57
|
x
|
53
58
|
else
|
54
59
|
Unit.new(x)
|
@@ -61,8 +66,9 @@ module Phys
|
|
61
66
|
find_unit(x) or raise UnitError, "Undefined unit: #{x.inspect}"
|
62
67
|
end
|
63
68
|
|
64
|
-
# Searches a registered unit and then
|
69
|
+
# Searches a registered unit and then parse as a unit string
|
65
70
|
# if not registered.
|
71
|
+
# @param [String,Symbol,Numeric,Unit,Quantity,NilClass] x
|
66
72
|
# @return [Phys::Unit]
|
67
73
|
def parse(x)
|
68
74
|
find_unit(x) || Unit.cast(Parse.new.parse(x))
|
@@ -70,15 +76,27 @@ module Phys
|
|
70
76
|
alias [] parse
|
71
77
|
|
72
78
|
# Searches a registered unit.
|
79
|
+
# @param [String,Symbol,Numeric,Unit,Quantity,NilClass] x
|
73
80
|
# @return [Phys::Unit, NilClass]
|
74
81
|
def find_unit(x)
|
75
|
-
|
82
|
+
case x
|
83
|
+
when String,Symbol
|
84
|
+
x = x.to_s.strip
|
85
|
+
if x==''
|
86
|
+
Unit.new(1)
|
87
|
+
else
|
88
|
+
LIST[x] || PREFIX[x] || find_prefix(x) || unit_stem(x)
|
89
|
+
end
|
90
|
+
when Numeric
|
76
91
|
Unit.new(x)
|
77
|
-
|
92
|
+
when NilClass
|
78
93
|
Unit.new(1)
|
94
|
+
when Unit
|
95
|
+
x
|
96
|
+
when Quantity
|
97
|
+
x.unit
|
79
98
|
else
|
80
|
-
|
81
|
-
LIST[x] || PREFIX[x] || find_prefix(x) || unit_stem(x)
|
99
|
+
raise TypeError, "Invalid argument: #{x.inspect}"
|
82
100
|
end
|
83
101
|
end
|
84
102
|
|
@@ -165,8 +183,7 @@ module Phys
|
|
165
183
|
end
|
166
184
|
|
167
185
|
if /^([^\s()\[\]{}!*|\/^#]+)\s+([^#]+)/ =~ str
|
168
|
-
|
169
|
-
Unit.define(name,repr)
|
186
|
+
Unit.define($1,$2.strip)
|
170
187
|
elsif !str.strip.empty?
|
171
188
|
puts "unrecognized definition: '#{str}'" if debug
|
172
189
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Phys
|
2
|
+
|
3
|
+
# @visibility private
|
4
|
+
module UnitMeasures
|
5
|
+
def self.included(mod)
|
6
|
+
Phys::Unit::LIST.each do |k,u|
|
7
|
+
if /^[A-Z]\w*$/ =~ k
|
8
|
+
const_set(k,u)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Defines method with unit name.
|
15
|
+
# *Caution*: Variable names may conflict with unit names.
|
16
|
+
# @example
|
17
|
+
# Phys::UnitsMixin.module_eval do
|
18
|
+
# puts 123.4*km
|
19
|
+
# puts (23*mile/hr).want(m/s)
|
20
|
+
# puts h.to_si
|
21
|
+
# case mile/hr
|
22
|
+
# when m
|
23
|
+
# puts "length"
|
24
|
+
# when m/s
|
25
|
+
# puts "velocity"
|
26
|
+
# else
|
27
|
+
# puts "other"
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# include Phys::UnitsMixin
|
32
|
+
#
|
33
|
+
# (1*miles/hr).want m/s #=> Phys::Quantity[0.44704,"m/s"]
|
34
|
+
#
|
35
|
+
module UnitsMixin
|
36
|
+
include UnitMeasures
|
37
|
+
module_function
|
38
|
+
alias method_missing_units_alias method_missing
|
39
|
+
def method_missing(method, *args, &block)
|
40
|
+
if unit=Phys::Unit.find_unit(method)
|
41
|
+
raise "argument must be empty" unless args.empty?
|
42
|
+
Phys::Quantity.new(1,method,unit)
|
43
|
+
else
|
44
|
+
method_missing_units_alias(method, *args, &block)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def print_units(unit=nil)
|
49
|
+
Phys::Unit::LIST.each do |k,u|
|
50
|
+
if unit.nil? || unit===u
|
51
|
+
len = 32 - k.size
|
52
|
+
len = 1 if len < 1
|
53
|
+
puts k+" "*len+"#{u.expr}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# ActiveSupport-like mix-in.
|
61
|
+
# *Caution*: This kind of global change will cause unexpected problems.
|
62
|
+
# @example
|
63
|
+
# class Numeric
|
64
|
+
# include Phys::UnitsNumericMixin
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# (1.miles/1.hr).want 'm/s' #=> Phys::Quantity[0.44704,"m/s"]
|
68
|
+
module UnitsNumericMixin
|
69
|
+
alias method_missing_units_alias method_missing
|
70
|
+
def method_missing(method, *args, &block)
|
71
|
+
if unit=Phys::Unit.find_unit(method)
|
72
|
+
raise "argument must be empty" unless args.empty?
|
73
|
+
Phys::Quantity.new(self,method,unit)
|
74
|
+
else
|
75
|
+
method_missing_units_alias(method, *args, &block)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
data/lib/phys/units/version.rb
CHANGED
data/spec/unit_spec.rb
CHANGED
@@ -38,7 +38,7 @@ describe "Create Units" do
|
|
38
38
|
its(:factor) {should == 1}
|
39
39
|
its(:conversion_factor) {should == Math::PI}
|
40
40
|
its(:name) {should == 'pi'}
|
41
|
-
its(:expr) {should
|
41
|
+
its(:expr) {should == '!dimensionless'}
|
42
42
|
its(:offset) {should be_nil}
|
43
43
|
its(:dimension) {should == {'pi'=>1}}
|
44
44
|
its(:dimension_value) {should == Math::PI}
|
@@ -53,7 +53,7 @@ describe "Create Units" do
|
|
53
53
|
its(:factor) {should == 1}
|
54
54
|
its(:conversion_factor) {should == 1}
|
55
55
|
its(:name) {should == 'm'}
|
56
|
-
its(:expr) {should
|
56
|
+
its(:expr) {should == '!'}
|
57
57
|
its(:offset) {should be_nil}
|
58
58
|
its(:dimension) {should == {'m'=>1}}
|
59
59
|
its(:dimension_value) {should == 1}
|
@@ -173,6 +173,7 @@ describe "Create Units" do
|
|
173
173
|
it {should_not be_dimensionless}
|
174
174
|
it {should_not be_scalar}
|
175
175
|
it {should be_operable}
|
176
|
+
it {should === Q[1,'miles/hr']}
|
176
177
|
end
|
177
178
|
|
178
179
|
describe U.parse('(m/s)**2') do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phys-units
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masahiro TANAKA
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
11
|
+
date: 2013-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -62,6 +62,7 @@ files:
|
|
62
62
|
- lib/phys/units/quanty.rb
|
63
63
|
- lib/phys/units/unit.rb
|
64
64
|
- lib/phys/units/unit_class.rb
|
65
|
+
- lib/phys/units/units_mixin.rb
|
65
66
|
- lib/phys/units/utils.rb
|
66
67
|
- lib/phys/units/version.rb
|
67
68
|
- misc/mkjpspec.rb
|