numeric_with_unit 0.0.4 → 0.1.0

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: d291b9eeb33681e615cf968e9ebf04564dea470b
4
- data.tar.gz: cfbd75a22e7f4ed618127772d481a18582461c13
3
+ metadata.gz: 757d20434e2556a232c44455278317111626a717
4
+ data.tar.gz: 29a86bf1e906c35b49104ede8013e07ff392aaba
5
5
  SHA512:
6
- metadata.gz: 596b5e89d9161c75f00e49fb392cbaa8ec2d7ab272b174443671d28e5b3c961dc68dc8fd822b335a4adc4c62457cc370c235b6a4d4c587640617726bda0797b3
7
- data.tar.gz: ca6f084096c236d63b2e327dc11795dc30d0043704ec8b752b7729ab4fcd80beab44db11d3a1d8c502b9535b56e9c4205926d36eaf8aee3da5d48ee55f195e8c
6
+ metadata.gz: 4ef1f289645e9fea40ec7674bc64c514355bef6705502214339b162d68f64153c230c768d1198315c6b0ff409d79835d8bb4751b4a82ff611cac119228eeee90
7
+ data.tar.gz: 70ea80a9ff0b464a69a1e64367e9365e80d532b9e4ab2a81b2cbcc5e6104101abf2da4195278bc75db106fea890cf7ad0b372dca71606376af1bd079c270901d
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 diaphragm
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,162 @@
1
+ ruby-numeric-with-unit
2
+ ======================
3
+ 単位付き数値を提供します。したいです。
4
+
5
+ インストール
6
+ ======================
7
+
8
+ $ gem install numeric_with_unit
9
+
10
+ 使い方
11
+ ======================
12
+
13
+ require 'numeric_with_unit'
14
+
15
+ #例1
16
+ length = NumericWithUnit.new(10, 'm') #10[m]を表すオブジェクトです。
17
+ puts length #=> 10 m
18
+ puts length['cm'] #=> 1000 cm
19
+
20
+ time = 10.to_nwu('s') #Fixnum#to_nwuが追加されるので、これを用いてもOKです。10[s]を表すオブジェクトです。
21
+ puts time #=> 10 s
22
+ puts time['min'] #=> 0.16666666666666666 min
23
+
24
+ speed = length / time
25
+ puts speed #=> 1 m/(s)
26
+ puts speed['km/hr'] #=> 3.6 km/(hr)
27
+
28
+ require 'numeric_with_unit/util' #自然な表記で記述できるようにします。
29
+ puts (10['m'] / 10['s'] )['km/hr'] #=> 3.6 km/(hr)
30
+
31
+ #例2
32
+ puts (50['L/min'] + 3['m3/hr'] ) * 30['min'] #=> 3000 L
33
+
34
+
35
+ * `require 'numeric_with_unit/util'`すると`Numeric#[]`と`Fixnum#[]`と`Bignum#[]`がオーバーライドされます。注意。
36
+
37
+
38
+ class NumericWith::Unit
39
+ ======================
40
+ "単位"を表すクラスです。
41
+
42
+ Unit.new
43
+ ----------------------
44
+
45
+ km = NumericWith::Unit.new do |conf|
46
+ conf.symbol = 'km'
47
+ conf.dimension[:L] = 1
48
+ conf.from_si{|x| x/1000}
49
+ conf.to_si{|x| x*1000}
50
+ end
51
+
52
+ `conf.from_si`と`conf.to_si`で、SI基本単位で表した場合の変換式を設定します。
53
+
54
+ Unit#cast
55
+ ----------------------
56
+ 1 mi = 1.609344 km
57
+ のような関係の単位は、
58
+
59
+ mi = km.cast('mi', 1.609344)
60
+
61
+ で生成できます。
62
+ ただし、n倍だけの関係に限ります。
63
+ ℃と℉のような関係の場合は`Unit.new`で新たに生成して下さい。
64
+
65
+ Unit<<, Unit[], Unit[]=
66
+ ----------------------
67
+ `Unit << unit`で、`unit`を基本単位として登録します。
68
+ 基本単位として登録することで、`Unit[]`から組立単位が自動的に導出されます。
69
+
70
+ NumericWith::Unit << km
71
+ NumericWith::Unit << NumericWith::Unit.new do |conf|
72
+ conf.symbol = 'hr'
73
+ conf.dimension[:T] = 1
74
+ conf.from_si{|x| x/60/60}
75
+ conf.to_si{|x| x*60*60}
76
+ end
77
+
78
+ puts NumericWith::Unit['km2'].symbol #=> km2
79
+ puts NumericWith::Unit['km/hr'].symbol #=> km/(hr)
80
+
81
+ 基本単位として登録されている単位は、`Unit.list`で得られます。
82
+
83
+ また`Unit[]=`で単位の変換と基本単位として登録を同時に行えます。
84
+
85
+ NumericWith::Unit['kph'] = 'km/hr'
86
+ NumericWith::Unit['ua'] = 1.495978706916e8, 'm'
87
+
88
+ ----
89
+ 基本的な単位は以下のファイルで定義済みです。
90
+ 適宜`require`してください。
91
+
92
+ * 'numeric_with_unit/unit_definition/base' (SI単位、SI組立単位およびSI併用単位を定義。デフォルトで`require`されます。)
93
+ * 'numeric_with_unit/unit_definition/common' (独断と偏見によりcommonと認定された単位。デフォルトで`require`されます。)
94
+ * 'numeric_with_unit/unit_definition/cgs' (未完成)
95
+ * 'numeric_with_unit/unit_definition/imperial' (未完成)
96
+ * 'numeric_with_unit/unit_definition/natural' (未完成)
97
+
98
+
99
+ class NumericWithUnit
100
+ ======================
101
+ 単位の情報を持った数値を表すクラスです。
102
+
103
+ 単位換算したり足したり引いたり掛けたり割ったり累乗したりできます。
104
+
105
+ NumericWithUnit.new(value, unit)
106
+ ----------------------
107
+ valueの数値とunitの単位を持つNumericWithUnitオブジェクトを返します。
108
+ unitには単位を表す文字列またはUnitクラスのオブジェクトを渡します。
109
+
110
+ Numeric#to_nwu(unit), Fixnum#to_nwu(unit), Bignum#to_nwu(unit)
111
+ ----------------------
112
+ NumericWithUnit.new(self, unit)を返します。
113
+
114
+ NumericWithUnit#value
115
+ ----------------------
116
+ 数値を返します。
117
+
118
+ NumericWithUnit#unit
119
+ ----------------------
120
+ Unitオブジェクトを返します。
121
+
122
+ NumericWithUnit#\[\](new_unit), NumericWithUnit#to_nwu(new_unit)
123
+ ----------------------
124
+ new_unitに変換したNumericWithUnitオブジェクトを返します。
125
+
126
+ selfと次元の異なる単位を指定した場合は、NumericWithUnit::DimensionErrorが発生します。
127
+
128
+ NumericWithUnit#+(other), NumericWithUnit#-(other)
129
+ ----------------------
130
+ otherがNumericWithUnitクラスの場合、selfの単位に変換し数値を加減したNumericWithUnitオブジェクトを返します。
131
+ otherがNumericWithUnitクラスでない場合、otherを無次元のNumericWithUnitにした上で加減します。
132
+
133
+ ohterとselfの次元が異なる場合は、NumericWithUnit#DimensionErrorが発生します。
134
+
135
+ NumericWithUnit#*(ohter), NumerichWithUnit#/(other)
136
+ ----------------------
137
+ otherがNumericWithUnitクラスの場合、selfとotherの組立単位を持つ、数値を乗除したNumericWithUnitオブジェクトを返します。
138
+ otherがNumericWithUnitクラスでない場合、otherを無次元のNumericWithUnitにした上で乗除します。
139
+
140
+ NumericWithUnit#**(num)
141
+ ----------------------
142
+ selfの単位をnum乗した組立単位を持つ、数値をnum乗したNumericWithUnitオブジェクトを返します。
143
+
144
+
145
+ 単位を表す文字列のフォーマット
146
+ ======================
147
+ Unit[]や、NumericWithUnit#[]には、単位を表す文字列を渡すことができます。
148
+ 例を示します。
149
+
150
+ - m
151
+ - cm
152
+ - m2
153
+ - kW.hr
154
+ - kg/cm2
155
+ - m.s-1
156
+ - J/kg/K
157
+ - kcal/(hr.m2.℃)
158
+
159
+ 先頭に接頭辞、末尾に指数をつけた基本単位を、"."または"/"で繋いだ形で表記します。
160
+ "()"で基本単位として括ることもできます。
161
+
162
+
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+
3
+ require 'numeric_with_unit'
4
+
5
+ class Fixnum
6
+ def to_nwu(unit)
7
+ NumericWithUnit.new(self, unit)
8
+ end
9
+ end
10
+
11
+ class Bignum
12
+ def to_nwu(unit)
13
+ NumericWithUnit.new(self, unit)
14
+ end
15
+ end
16
+
17
+ class Numeric
18
+ def to_nwu(unit)
19
+ NumericWithUnit.new(self, unit)
20
+ end
21
+ end
22
+
23
+ class String
24
+ def to_nwu(mthd=:to_r)
25
+ # TODO: 適当なのでもう少しいい感じに。いい感じに
26
+ m = self.match /.*?(?=[\s\(\[])/
27
+ value = m.to_s
28
+ unit = m.post_match.strip.gsub(/^\[|\]$/, '')
29
+ NumericWithUnit.new(value.__send__(mthd), unit)
30
+ end
31
+ end
32
+
@@ -106,10 +106,11 @@ class NumericWithUnit
106
106
  # class methods
107
107
 
108
108
  # create new unit from derivation _(for internal use)_ .
109
- def self.derive
109
+ def self.derive #(block)
110
110
  derivation = Hash.new(0)
111
111
  yield(derivation)
112
112
  return Unit.new if derivation.empty?
113
+
113
114
  derivation.delete_if{|k,v| k.symbol.nil?}
114
115
 
115
116
  # constructing symbol
@@ -117,7 +118,7 @@ class NumericWithUnit
117
118
  syms_pos = h.select{|u,v| v > 0}.map{|u,v| u.symbol + (v.abs>1 ? v.abs.to_s : '')}
118
119
  syms_neg = h.select{|u,v| v < 0}.map{|u,v| u.symbol + (v.abs>1 ? v.abs.to_s : '')}
119
120
  symbol = syms_pos.join('.')
120
- symbol += '/' + (syms_neg.size==1 ? "#{syms_neg.first}" : "(#{syms_neg.join('.')})") unless syms_neg.empty?
121
+ symbol += '/' + (syms_neg.size>1 ? "(#{syms_neg.join('.')})" : "#{syms_neg.first}") unless syms_neg.empty?
121
122
 
122
123
  # constructing dimension
123
124
  dimension = Hash.new(0)
@@ -132,7 +133,7 @@ class NumericWithUnit
132
133
  prc = if v > 0
133
134
  ->(x){u.from_si(x)}
134
135
  else
135
- ->(x){x.quo(u.from_si(1)-u.from_si(0))} # ℃とKの変換のような場合に、変換式の切片を消すため。変換式が線形じゃないケースは想定していない
136
+ ->(x){x.quo(u.from_si(1)-u.from_si(0))} #FIXME: ℃とKの変換のような場合に、変換式の切片を消すため。変換式が線形じゃないケースは想定していない
136
137
  end
137
138
  [prc, v.abs]
138
139
  }.map{|prc,v|
@@ -146,7 +147,7 @@ class NumericWithUnit
146
147
  prc = if v > 0
147
148
  ->(x){u.to_si(x)}
148
149
  else
149
- ->(x){x.quo(u.to_si(1)-u.to_si(0))} # ℃とKの変換のような場合に、変換式の切片を消すため。変換式が線形じゃないケースは想定していない
150
+ ->(x){x.quo(u.to_si(1)-u.to_si(0))} #FIXME: ℃とKの変換のような場合に、変換式の切片を消すため。変換式が線形じゃないケースは想定していない
150
151
  end
151
152
  [prc, v.abs]
152
153
  }.map{|prc,v|
@@ -183,7 +184,7 @@ class NumericWithUnit
183
184
 
184
185
  # return base unit list.
185
186
  def self.list
186
- @@list.map(&:symbol)
187
+ @@list
187
188
  end
188
189
 
189
190
  # add unit to base unit list.
@@ -307,7 +308,7 @@ class NumericWithUnit
307
308
  rec[x, derivation, order]
308
309
  end
309
310
  else
310
- raise StandardError, "maybe bug"
311
+ raise StandardError, %(maybe bug in "numeric_with_unit" gem)
311
312
  end
312
313
  derivation
313
314
  end
@@ -326,7 +327,7 @@ class NumericWithUnit
326
327
  attr_reader :dimension, :derivation
327
328
 
328
329
  def initialize(derivation=nil)
329
- # Unit::Configとinitializeの役割が分離できていないので見なおせ
330
+ # TODO: Unit::Configとinitializeの役割が分離できていないので見なおせ
330
331
  config = Config.new
331
332
  yield(config) if block_given?
332
333
  config.compile
@@ -358,12 +359,16 @@ class NumericWithUnit
358
359
  @symbol
359
360
  end
360
361
 
362
+ def inspect
363
+ "#<#{self.class}:[#{@symbol}] #{@dimension}>"
364
+ end
365
+
361
366
  def to_si(value)
362
- @to_si[value]
367
+ @to_si.call(value)
363
368
  end
364
369
 
365
370
  def from_si(value)
366
- @from_si[value]
371
+ @from_si.call(value)
367
372
  end
368
373
 
369
374
 
@@ -405,6 +410,7 @@ class NumericWithUnit
405
410
  self.class.new
406
411
  else
407
412
  self.class.derive do |derivation|
413
+ # NOTE:
408
414
  # ここto_iでOKか?v*numが整数じゃなければraiseすべき?→すべき→NumericWithUnitでやるべき?
409
415
  # Unitでは整数じゃない次数の単位は許容すべきか否か→していい気がする
410
416
  @derivation.each{|k, v| derivation[k] = (v*num).to_i}
@@ -412,6 +418,17 @@ class NumericWithUnit
412
418
  end
413
419
  end
414
420
 
421
+
422
+ def simplify
423
+ self.class.derive{|derivation|
424
+ @dimension.each do|d,o|
425
+ u = self.class.list.find{|u| u.dimension == {d => 1}} #TODO: find? ok?
426
+ raise NoUnitError, "No unit with #{{d=>1}} dimension is assined." unless u
427
+ derivation[u] = o
428
+ end
429
+ }
430
+ end
431
+
415
432
  end
416
433
 
417
434
  class Unit
@@ -48,7 +48,7 @@ class NumericWithUnit
48
48
  # Thermodynamic Temperature
49
49
  Unit << Unit.new do |conf|
50
50
  conf.symbol = 'K'
51
- conf.dimension[] = 1
51
+ conf.dimension[:THETA] = 1
52
52
  conf.si = true
53
53
  end
54
54
 
@@ -120,16 +120,16 @@ class NumericWithUnit
120
120
  # Inductance
121
121
  Unit['H'] = 'V.s/A'
122
122
 
123
- # Temperature
124
- Unit << Unit.new do |conf|
125
- k = Unit['K']
126
- intercept = "273.15".to_r
127
-
128
- conf.symbol = '℃'
129
- conf.dimension = k.dimension
130
- conf.from_si{|x| k.from_si(x)-intercept}
131
- conf.to_si{|x| k.to_si(x+intercept)}
132
- end
123
+ # # Temperature
124
+ # Unit << Unit.new do |conf|
125
+ # k = Unit['K']
126
+ # intercept = "273.15".to_r
127
+ #
128
+ # conf.symbol = '℃'
129
+ # conf.dimension = k.dimension
130
+ # conf.from_si{|x| k.from_si(x)-intercept}
131
+ # conf.to_si{|x| k.to_si(x+intercept)}
132
+ # end
133
133
 
134
134
  # Luminouse flux
135
135
  Unit['lx'] = 'cd.sr'
File without changes
@@ -19,24 +19,24 @@ class NumericWithUnit
19
19
 
20
20
  # Mass
21
21
  Unit['ton'] = 1000, 'kg'
22
- Unit['oz'] = "28.349523125".to_r, 'g'
23
- Unit['lb'] = 16, 'oz'
22
+ Unit['lb'] = "0.45359237".to_r, 'kg' # 常用ポンド
23
+ Unit['oz'] = "1/16".to_r, 'lb' # 常用オンス
24
24
 
25
25
  # Electriccal Resistance
26
26
  Unit['ohm'] = 'Ω'
27
27
 
28
28
  # Temperature
29
- Unit['degC'] = '℃'
29
+ # Unit['degC'] = '℃'
30
30
  Unit['degR'] = "5/9".to_r, 'K'
31
- Unit << Unit.new do |conf|
32
- degr = Unit['degR']
33
- intercept = "459.67".to_r
34
-
35
- conf.symbol = 'degF'
36
- conf.dimension = degr.dimension
37
- conf.from_si{|x| degr.from_si(x)-intercept}
38
- conf.to_si{|x| degr.to_si(x+intercept)}
39
- end
31
+ # Unit << Unit.new do |conf|
32
+ # degr = Unit['degR']
33
+ # intercept = "459.67".to_r
34
+ #
35
+ # conf.symbol = 'degF'
36
+ # conf.dimension = degr.dimension
37
+ # conf.from_si{|x| degr.from_si(x)-intercept}
38
+ # conf.to_si{|x| degr.to_si(x+intercept)}
39
+ # end
40
40
 
41
41
  # Length
42
42
  Unit['Å'] = 10**-10, 'm'
@@ -48,7 +48,8 @@ class NumericWithUnit
48
48
 
49
49
  # Volume
50
50
  Unit['cc'] = 'cm3'
51
- Unit['bbl'] = "0.158987294928".to_r, 'm3'
51
+ Unit['gal'] = 231, 'in3' # 米液量ガロン
52
+ Unit['bbl'] = 42, 'gal' # 石油要バレル
52
53
 
53
54
  # Force
54
55
  Unit['kgf'] = "9.80665".to_r, 'N'
@@ -66,24 +67,25 @@ class NumericWithUnit
66
67
  Unit['mHg'] = "1/1000".to_r, 'mmHg' # for compatible
67
68
  Unit['mH2O'] = "9806.65".to_r, 'Pa'
68
69
  Unit['mAq'] = 'mH2O'
69
- Unit['psi'] = "6894.76".to_r, 'Pa'
70
-
71
- # Guage圧の扱いどうしようか?
72
- Unit << Unit.new do |conf|
73
- pa = Unit['Pa']
74
- atm = 101325
75
-
76
- conf.symbol = 'PaG'
77
- conf.dimension = pa.dimension
78
- conf.from_si{|x| pa.from_si(x)-atm}
79
- conf.to_si{|x| pa.to_si(x+atm)}
80
- end
70
+ Unit['psi'] = 'lbf/in2'
71
+
72
+ # # Guage圧の扱いどうしようか?
73
+ # Unit << Unit.new do |conf|
74
+ # pa = Unit['Pa']
75
+ # atm = 101325
76
+ #
77
+ # conf.symbol = 'PaG'
78
+ # conf.dimension = pa.dimension
79
+ # conf.from_si{|x| pa.from_si(x)-atm}
80
+ # conf.to_si{|x| pa.to_si(x+atm)}
81
+ # end
81
82
 
82
83
  # Speed
83
84
  Unit['kph'] = 'km/hr'
84
85
 
85
86
  # Flowrate
86
87
  Unit['lpm'] = 'L/min'
88
+ Unit['CMH'] = 'm3/hr'
87
89
 
88
90
  # Viscosity
89
91
  Unit['P'] = "1/10".to_r, 'Pa.s'
@@ -0,0 +1,44 @@
1
+ # coding: utf-8
2
+
3
+ #
4
+ # 変換に対応しきれていない単位
5
+ # 四則演算を交える場合に要注意
6
+ #
7
+
8
+ require 'numeric_with_unit/unit_definition/base'
9
+
10
+ class NumericWithUnit
11
+ # Temperature
12
+ Unit << Unit.new do |conf|
13
+ k = Unit['K']
14
+ intercept = "273.15".to_r
15
+
16
+ conf.symbol = '℃'
17
+ conf.dimension = k.dimension
18
+ conf.from_si{|x| k.from_si(x)-intercept}
19
+ conf.to_si{|x| k.to_si(x+intercept)}
20
+ end
21
+
22
+ Unit['degC'] = '℃'
23
+
24
+ Unit << Unit.new do |conf|
25
+ degr = Unit['degR']
26
+ intercept = "459.67".to_r
27
+
28
+ conf.symbol = 'degF'
29
+ conf.dimension = degr.dimension
30
+ conf.from_si{|x| degr.from_si(x)-intercept}
31
+ conf.to_si{|x| degr.to_si(x+intercept)}
32
+ end
33
+
34
+ # Pressure
35
+ Unit << Unit.new do |conf|
36
+ pa = Unit['Pa']
37
+ atm = 101325
38
+
39
+ conf.symbol = 'PaG'
40
+ conf.dimension = pa.dimension
41
+ conf.from_si{|x| pa.from_si(x)-atm}
42
+ conf.to_si{|x| pa.to_si(x+atm)}
43
+ end
44
+ end
File without changes
File without changes
@@ -8,7 +8,7 @@ require 'numeric_with_unit'
8
8
  class NumericWithUnit
9
9
  module NumUtil
10
10
  def [](unit)
11
- NumericWithUnit.new(self.rationalize, unit) # ratoinalizeする?
11
+ NumericWithUnit.new(self, unit)
12
12
  end
13
13
  end
14
14
  end
@@ -1,6 +1,7 @@
1
1
  # coding: utf-8
2
2
 
3
3
  # 123.m2.K_W のように書けるようにします。
4
+ # 123.cP.mPa.s のように単位の換算(cP -> mPa.s)も可能です。
4
5
  # method_missing をオーバーライドします。
5
6
 
6
7
  require 'numeric_with_unit'
@@ -9,7 +10,7 @@ class NumericWithUnit
9
10
  def method_missing(name, *args)
10
11
  if args.empty?
11
12
  unit_str = name.to_s.gsub('_', '/')
12
- unit_chain_util(Unit[unit_str])
13
+ resolve_unit_chain(Unit[unit_str])
13
14
  else
14
15
  raise Unit::NoUnitError
15
16
  end
@@ -18,20 +19,21 @@ class NumericWithUnit
18
19
  end
19
20
 
20
21
  attr_writer :unit_chain
22
+ protected :unit_chain=
21
23
 
22
24
  private
23
- def unit_chain_util(unit)
24
- ucs = @unit_chain || []
25
- ucs.map!{|nwu, u| [nwu, u * unit]}
26
- ucs << [self, unit]
25
+ def resolve_unit_chain(unit)
26
+ unit_chain = @unit_chain || []
27
+ unit_chain.map!{|nwu, chained_unit| [nwu, chained_unit * unit]}
28
+ unit_chain << [self, unit]
27
29
 
28
- if i = ucs.index{|nwu, u| nwu.unit.dimension_equal? u}
29
- nwu, nu = *ucs[i]
30
- nwu[nu]
30
+ if i = unit_chain.index{|nwu, chained_unit| nwu.unit.dimension_equal? chained_unit}
31
+ nwu, chained_unit = *unit_chain[i]
32
+ nwu.convert(chained_unit)
31
33
  else
32
- nnwu = self.class.new(@value, @unit*unit)
33
- nnwu.unit_chain = ucs
34
- nnwu
34
+ newnwu = self.class.new(@value, @unit*unit)
35
+ newnwu.unit_chain = unit_chain
36
+ newnwu
35
37
  end
36
38
  end
37
39
  end
@@ -42,7 +44,7 @@ class NumericWithUnit
42
44
  def method_missing(name, *args)
43
45
  if args.empty?
44
46
  unit_str = name.to_s.gsub('_', '/')
45
- self.rationalize.to_nwu(unit_str) # util2は利便性優先なのでratoinalizeしてしまいます
47
+ self.to_f.to_nwu(unit_str) # util2は利便性優先なのでto_fしてしまいます
46
48
  else
47
49
  raise Unit::NoUnitError
48
50
  end
@@ -4,68 +4,84 @@ require 'numeric_with_unit/unit'
4
4
 
5
5
  class NumericWithUnit
6
6
  include Comparable
7
-
7
+
8
8
  attr_reader :value, :unit
9
-
9
+
10
10
  def initialize(value, unit)
11
11
  @value = value
12
12
  @unit = unit.is_a?(Unit) ? unit : Unit[unit]
13
13
  end
14
-
14
+
15
15
  # Return String for inspect
16
16
  def inspect
17
- "#{@value.inspect} [#{@unit.symbol}] #{unit.dimension.inspect}"
17
+ "#{@value.inspect} [#{@unit.symbol}] #{@unit.dimension.inspect}"
18
18
  end
19
-
19
+
20
20
  # Return String with value and unit symbol
21
21
  def to_s
22
22
  "#{@value.to_s} #{@unit.symbol}"
23
23
  end
24
-
24
+
25
25
  # If ohter is NumericWithUnit and same dimension, comparing value with converting to si.
26
26
  # Else return nil.
27
27
  def <=>(other)
28
28
  if other.is_a?(self.class) and @unit.dimension_equal? other.unit
29
- @unit.to_si(@value) <=> other.unit.to_si(other.value)
29
+ value_si <=> other.value_si
30
30
  end
31
31
  end
32
-
32
+
33
+ def ===(other)
34
+ self.<=>(other) == 0
35
+ end
36
+
33
37
  # Return succed value with same unit.
34
38
  def succ
35
39
  self.class.new(@value.succ, @unit)
36
40
  end
37
-
41
+
38
42
  # Return value.to_i
39
43
  def to_i
40
44
  @value.to_i
41
45
  end
42
-
46
+
43
47
  # Return value.to_f
44
48
  def to_f
45
49
  @value.to_f
46
50
  end
47
-
48
- # Return NumericWithUnit with given unit
49
- def to_nwu(unit)
51
+
52
+ # Return value in si
53
+ def value_si
54
+ @unit.to_si(@value)
55
+ end
56
+
57
+ # Convert to given unit
58
+ def convert(unit)
50
59
  new_unit = unit.is_a?(Unit) ? unit : Unit[unit]
51
-
60
+
52
61
  unless @unit.dimension_equal? new_unit
53
62
  raise DimensionError, "Dimensions are different between #{@unit.symbol}#{@unit.dimension} #{new_unit.symbol}#{new_unit.dimension}"
54
63
  end
55
-
64
+
56
65
  new_value = new_unit.from_si(@unit.to_si(@value))
57
66
  self.class.new(new_value, new_unit)
58
67
  end
59
- alias :[] :to_nwu
60
-
68
+ alias :to_nwu :convert
69
+ alias :[] :convert
70
+
71
+ # Convert to simple unit
72
+ def simplify
73
+ convert(@unit.simplify)
74
+ end
75
+
76
+
61
77
  def +@
62
78
  self
63
79
  end
64
-
80
+
65
81
  def -@
66
82
  self.class.new(-@value, @unit)
67
83
  end
68
-
84
+
69
85
  def +(other)
70
86
  nwu = if other.is_a? self.class
71
87
  other
@@ -74,11 +90,11 @@ class NumericWithUnit
74
90
  end
75
91
  add_with_other_unit(nwu)
76
92
  end
77
-
93
+
78
94
  def -(other)
79
95
  self + (-other)
80
96
  end
81
-
97
+
82
98
  def *(other)
83
99
  case other
84
100
  when self.class
@@ -87,7 +103,7 @@ class NumericWithUnit
87
103
  self.class.new(@value*other, @unit)
88
104
  end
89
105
  end
90
-
106
+
91
107
  def /(other)
92
108
  case other
93
109
  when self.class
@@ -96,7 +112,7 @@ class NumericWithUnit
96
112
  self.class.new(@value/other, @unit)
97
113
  end
98
114
  end
99
-
115
+
100
116
  def coerce(other)
101
117
  if other.is_a?(self.class)
102
118
  [other, self]
@@ -104,25 +120,47 @@ class NumericWithUnit
104
120
  [self.class.new(other, Unit.new), self]
105
121
  end
106
122
  end
107
-
123
+
108
124
  def **(num)
109
125
  # Dimension Check
110
- @unit.derivation.each do |k,v|
111
- res = v * num
112
- raise DimensionError, "Dimension of #{k.symbol}(#{v}*#{num}) must be Integer" unless res.to_i == res # 判定方法見なおせ
113
- end
114
-
115
- self.class.new(@value**num, @unit**num)
126
+ if @unit.derivation.all?{|k,v| o = v * num; o.to_i == o} # TODO: 整数かどうかの判定方法いいのこれで
127
+ self.class.new(@value**num, @unit**num)
128
+ else
129
+ nu = @unit.simplify
130
+ if nu.derivation.all?{|k,v| o = v * num; o.to_i == o}
131
+ nv = nu.from_si(@unit.to_si(@value))
132
+ self.class.new(nv ** num, nu**num)
133
+ else
134
+ raise DimensionError, "All derivating units order multiplied #{num} must be integer"
135
+ end
136
+ end
116
137
  end
117
-
138
+
118
139
  def root(num)
119
140
  self**(Rational(1,num))
120
141
  end
121
142
  def sqrt; root(2) end # 平方根
122
143
  def cbrt; root(3) end # 立方根
123
-
144
+
145
+ def ceil
146
+ self.class.new(@value.ceil, @unit)
147
+ end
148
+
149
+ def floor
150
+ self.class.new(@value.floor, @unit)
151
+ end
152
+
153
+ def round
154
+ self.class.new(@value.round, @unit)
155
+ end
156
+
157
+ def truncate
158
+ self.class.new(@value.truncate, @unit)
159
+ end
160
+
161
+
124
162
  private
125
-
163
+
126
164
  def add_with_other_unit(other)
127
165
  if @unit.dimension_equal? other.unit
128
166
  v1 = @unit.to_si(@value)
@@ -133,12 +171,12 @@ class NumericWithUnit
133
171
  raise DimensionError, "Dimensions are different between #{@unit.dimension} #{other.unit.dimension}"
134
172
  end
135
173
  end
136
-
174
+
137
175
  def multiply_with_other_unit(other)
138
176
  onwu = adjust_other_unit(other)
139
177
  self.class.new(@value * onwu.value, @unit * onwu.unit)
140
178
  end
141
-
179
+
142
180
  def devide_with_other_unit(other)
143
181
  onwu = adjust_other_unit(other)
144
182
  self.class.new(@value / onwu.value, @unit / onwu.unit)
@@ -156,7 +194,7 @@ class NumericWithUnit
156
194
  other
157
195
  end
158
196
  end
159
-
197
+
160
198
  end
161
199
 
162
200
 
@@ -167,37 +205,8 @@ end
167
205
 
168
206
 
169
207
 
170
- class Fixnum
171
- def to_nwu(unit)
172
- NumericWithUnit.new(self, unit)
173
- end
174
- end
175
-
176
- class Bignum
177
- def to_nwu(unit)
178
- NumericWithUnit.new(self, unit)
179
- end
180
- end
181
-
182
- class Numeric
183
- def to_nwu(unit)
184
- NumericWithUnit.new(self, unit)
185
- end
186
- end
187
-
188
- class String
189
- def to_nwu(mthd=:to_r)
190
- # 適当
191
- m = self.match /.*?(?=[\s\(\[])/
192
- value = m.to_s
193
- unit = m.post_match.strip.gsub(/^\[|\]$/, '')
194
- NumericWithUnit.new(value.__send__(mthd), unit)
195
- end
196
- end
197
-
198
-
208
+ require 'numeric_with_unit/core_ext'
199
209
 
200
210
  # unit definition
201
211
  require 'numeric_with_unit/unit_definition/base'
202
212
  require 'numeric_with_unit/unit_definition/common'
203
-
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: numeric_with_unit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - diaphragm
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-04 00:00:00.000000000 Z
11
+ date: 2016-02-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: This gem provide NumericWithUnit class to calculate numeric with unit
14
14
  of measurement.
@@ -17,11 +17,15 @@ executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
+ - LICENSE
21
+ - README.md
20
22
  - lib/numeric_with_unit.rb
23
+ - lib/numeric_with_unit/core_ext.rb
21
24
  - lib/numeric_with_unit/unit.rb
22
25
  - lib/numeric_with_unit/unit_definition/base.rb
23
26
  - lib/numeric_with_unit/unit_definition/cgs.rb
24
27
  - lib/numeric_with_unit/unit_definition/common.rb
28
+ - lib/numeric_with_unit/unit_definition/deprecated.rb
25
29
  - lib/numeric_with_unit/unit_definition/imperial.rb
26
30
  - lib/numeric_with_unit/unit_definition/natural.rb
27
31
  - lib/numeric_with_unit/util.rb
@@ -46,7 +50,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
46
50
  version: '0'
47
51
  requirements: []
48
52
  rubyforge_project:
49
- rubygems_version: 2.4.5
53
+ rubygems_version: 2.5.1
50
54
  signing_key:
51
55
  specification_version: 4
52
56
  summary: Numerical calculation with unit of measurement