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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c123870463b0713958805751bbcef484dc35d1dc
4
- data.tar.gz: 8a7bd323be840936ea2b3535b8a5bf6e312f5b4d
3
+ metadata.gz: f0ec7810800a733cda3aa7f753bf10d11b76891d
4
+ data.tar.gz: b2c93b618d876183ea89ebfab9e6f353a6160746
5
5
  SHA512:
6
- metadata.gz: efbbc5b61cb7a9eebf65f0e2420073365750321f502b24aeecc45afa9cc42f01b6a895f126383e4a3cf49e3cf8178a230602c3fed460a6d7ebcda678e756083a
7
- data.tar.gz: f1657606f20fadf5ff43744261b334322538ede36f93d89921f9afd7cbc68af5de040a67b2ccb0d56fda09e5a08afce03c9250fdcd27bc76052bbe4a46002bcf
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
- ## Phys::Quantity
8
- is the primary class of Phys-Units library, to be manipulated by users.
9
- It contains:
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
- See [Phys::Quantity Documentation](http://rubydoc.info/gems/phys-units/frames/Phys/Quantity)
20
- for more details.
38
+ Phys::Quantity[2.5,"miles"].unit #=> #<Phys::Unit 1609.344,{"m"=>1},@expr="5280 ft">
21
39
 
22
- ## Installation
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
- Install from gem as:
46
+ * *Factor* of the unit is a scale factor relative to its base unit.
25
47
 
26
- $ gem install phys-units
48
+ Phys::Unit["km"].factor #=> 1000
27
49
 
28
- Or install from source tree:
50
+ * *Dimension* of the unit
51
+ is a hash table containing base units and dimensions as key-value pairs.
29
52
 
30
- $ ruby setup.rb
53
+ Phys::Unit["N"].dimension #=> {"kg"=>1, "m"=>1, "s"=>-2}
31
54
 
32
- ## Usage
55
+ ### Examples
33
56
 
34
- require 'phys/units'
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 discriminated from many other units libraies for Ruby,
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
- * No addition or modification to Ruby standard classes,
54
- avoiding conflict with other libraries.
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
@@ -6,3 +6,4 @@ require "phys/units/utils.rb"
6
6
  require "phys/units/parse.rb"
7
7
  require "phys/units/quantity.rb"
8
8
  require "phys/units/load_units.rb"
9
+ require "phys/units/units_mixin.rb"
@@ -1,18 +1,5 @@
1
1
  require "phys/units"
2
2
 
3
- # ActiveSupport-like mix-in to Numeric.
4
- # This is activated by:
5
- # require 'phys/units/mixin'
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
@@ -723,7 +723,7 @@ module_eval(<<'.,.,', 'parse.y', 31)
723
723
 
724
724
  module_eval(<<'.,.,', 'parse.y', 35)
725
725
  def _reduce_10(val, _values, result)
726
- result = Unit.rdiv(val[0],val[2])
726
+ result = val[0] / val[2]
727
727
  result
728
728
  end
729
729
  .,.,
@@ -33,7 +33,7 @@ rule
33
33
  ;
34
34
 
35
35
  numexpr: NUMBER
36
- | numexpr '|' numexpr { result = Unit.rdiv(val[0],val[2]) }
36
+ | numexpr '|' numexpr { result = val[0] / val[2] }
37
37
  ;
38
38
 
39
39
  pexpr: '(' expr ')' { result = val[1] }
@@ -14,19 +14,27 @@ module Phys
14
14
  # Quantity.new(*a)
15
15
  #end
16
16
 
17
- # Phys::Quantity is a class to represent physical quantities
18
- # with unit of measure.
19
- # It contains:
20
- # * *Value* of the quantity.
21
- # +value+ must be a class instance having arithmetic methods,
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
- # * *Unit* of the quantity.
25
- # +unit+ is a instance of Phys::Unit class
26
- # obtained by parsing a +expr+ string.
27
- #== Usage
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
- # @param [Object] value
42
- # Value of quantity.
43
- # @param [String] expr a string of unit expression.
44
- # If +expr+ is not supplied, it becomes dimeinsionless.
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 [Phys::UnitError] if unit conversion is failed.
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
- # @param [Object] value
54
- # Value of quantity.
55
- # @param [String] expr a string of unit expression.
56
- # If +expr+ is not supplied, it becomes dimeinsionless.
57
- # @param [Phys::Unit] unit (optional)
58
- # @raise [Phys::UnitError] if unit conversion is failed.
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
- expr = expr.to_s if Symbol===expr
63
- @expr = (expr=='') ? nil : expr
64
- @unit = unit
65
- if @unit.nil?
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
- elsif !@unit.kind_of? Unit
68
- raise ArgumentError, "third arg must be Phys::Unit"
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 Numric.
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] expr unit expression.
88
- # @return [Phys::Quantity] quantity in the unit of +expr+.
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(expr)
92
- unit = Unit.parse(expr)
93
- val = unit.convert(self)
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 greather-than or equal-to +other+.
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_]+&/o =~ @expr
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
- self.class.to_s+"["+Unit::Utils.num_inspect(@value)+expr+"] "+@unit.inspect
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
@@ -9,22 +9,24 @@
9
9
 
10
10
  module Phys
11
11
 
12
- # Phys::Unit is a class to represent Physical Unit of Measure.
13
- # It must have:
14
- # * *Factor* of the unit. Conversion factor to +dimension+,
15
- # i.e., its base units.
16
- # * *Dimension* of the unit.
17
- # Dimension is a hash table with base units and dimension values.
18
- # Example:
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
- #== Usage
21
+ # @example
21
22
  # require "phys/units"
22
23
  # Q = Phys::Quantity
23
24
  # U = Phys::Unit
24
25
  #
25
- # U["miles"] / U["hr"] #=> #<Phys::Unit 0.44704,{"m"=>1, "s"=>-1}>
26
- # U["hr"] + U["30 min"] #=> #<Phys::Unit 5400,{"s"=>1}>
27
- # U["(m/s)"]**2 #=> #<Phys::Unit 1,{"m"=>2, "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 conversion factor.
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 invalit arg types.
66
+ # @raise [TypeError] if invalid arg types.
62
67
  #
63
- def initialize(arg,extr=nil)
64
- case arg
68
+ def initialize(a1,a2=nil)
69
+ case a1
65
70
  when Numeric
66
- arg = Rational(arg) if Integer===arg
67
- @factor = arg
68
- alloc_dim(extr)
71
+ a1 = Rational(a1) if Integer===a1
72
+ @factor = a1
73
+ alloc_dim(a2)
69
74
  when Phys::Unit
70
- @factor = arg.factor
71
- alloc_dim arg.dim
72
- @name = extr
75
+ @factor = a1.factor
76
+ alloc_dim a1.dim
77
+ @name = a2.strip if a2
73
78
  when String
74
- @expr = arg
75
- @name = extr
79
+ @expr = a1.strip
80
+ @name = a2.strip if a2
76
81
  else
77
- raise TypeError,"invalid argument : #{arg.inspect}"
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
- # Conversion factor except the dimension-value.
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. Returns PI number for pi dimension,
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
- #a << "@name="+@name.inspect if @name
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 unit string from dimension.
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-dimension, and its factor is one.
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 allowed.
252
- # @param [Object] x other object (unit or quantity or numeric or other)
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 conformable?(x)
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 === conformable?
267
- alias compatible? conformable?
268
- alias conversion_allowed? conformable?
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-dimension.
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 "dimensin not defined"
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 "dimensin not defined"
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 "!" in unit.dat
552
- # including SI units.
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
- dimles = (expr == "!dimensionless")
557
- LIST[name] = self.new(name,dimles,dimval)
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,dimless=false,dimval=nil)
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
- @dimensionless = dimless
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 "BaseUnit#initialize: arg must be string: #{s}"
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
- # Focused on Farenheight/Celsius temperature.
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 Quantitiy: #{quantity.inspect}"
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 New Unit. Expression is not parsed in this method.
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
- if !(String===name)
26
- raise TypeError,"unit name should be string : #{name.inspect}"
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
- dimless = (expr == "!dimensionless")
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
- if x.kind_of?(Unit)
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 Parse as a unit string
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
- if Numeric===x
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
- elsif x=='' || x.nil?
92
+ when NilClass
78
93
  Unit.new(1)
94
+ when Unit
95
+ x
96
+ when Quantity
97
+ x.unit
79
98
  else
80
- x = x.to_s
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
- name,repr = $1,$2.strip
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
@@ -1,5 +1,5 @@
1
1
  module Phys
2
2
  class Unit
3
- VERSION = "0.9.3"
3
+ VERSION = "0.9.4"
4
4
  end
5
5
  end
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 be_nil}
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 be_nil}
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.3
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-03 00:00:00.000000000 Z
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