phys-units 0.9.3 → 0.9.4

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: 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