numru-units 1.7.0

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.
data/src/Makefile ADDED
@@ -0,0 +1,35 @@
1
+ all: units.rb
2
+
3
+ units.rb: units.racc
4
+ racc -E -l units.racc -o tmp.rb
5
+ (ruby -n -e 'if /^class Units/; print("module NumRu\n",$$_); elsif /end\s*#\s*class\s*Units/; print($$_,"end # module NumRu\n"); else print $$_; end' tmp.rb > units.rb)
6
+ (( echo ; echo '####################' ; echo 'if $$0 == __FILE__' ; tail -n +2 test.rb | ruby -p -e 'print " "' ; echo 'end' ) >> units.rb)
7
+ @rm tmp.rb
8
+
9
+ test: units.rb
10
+ ruby test.rb
11
+
12
+ backup: units.shar
13
+ scp units.shar toyoda@www.gfd-dennou.org:tmp/
14
+ scp units.shar toyoda@pandora0.sytes.net:tmp/
15
+
16
+ RSRCS = rules.rb node.rb namenode.rb utab.rb numbernode.rb timenode.rb \
17
+ pownode.rb mulnode.rb shiftnode.rb lex.rb
18
+
19
+ utab.rb: makeutab.rb dcunits.txt
20
+ ruby makeutab.rb dcunits.txt > $@.tmp
21
+ mv $@.tmp $@
22
+
23
+ units.racc: $(RSRCS)
24
+ cat $(RSRCS) > $@.tmp
25
+ mv $@.tmp $@
26
+
27
+ edit:
28
+ $${EDITOR:-vi} $(RSRCS)
29
+
30
+ SRCS = Makefile units.rb dcunits.txt makeutab.rb $(RSRCS) test.rb units.rd
31
+
32
+ shar: units.shar
33
+
34
+ units.shar: $(SRCS)
35
+ shar $(SRCS) > units.shar
data/src/dcunits.txt ADDED
@@ -0,0 +1,212 @@
1
+ s S
2
+ second P s
3
+ m S
4
+ metre P m
5
+ meter P metre
6
+ kg S
7
+ kilogram P kg
8
+ A S
9
+ ampere P A
10
+ K S
11
+ kelvin P K
12
+ degK P K
13
+ deg_K P K
14
+ degreeK P K
15
+ mol S
16
+ mole P mol
17
+ rad S
18
+ radian P rad
19
+ sr S
20
+ steradian P sr
21
+ #
22
+ # --- standard named units ---
23
+ #
24
+ Hz S 1/s
25
+ hertz P Hz
26
+ N S kg.m.s-2
27
+ newton P N
28
+ Pa S N.m-2
29
+ pascal P Pa
30
+ Pascal P Pa
31
+ J S N.m
32
+ joule P J
33
+ W S J/s
34
+ watt P W
35
+ C S A.s
36
+ coulomb P C
37
+ V S J/C
38
+ volt P V
39
+ F S C/V
40
+ ohm S V/A
41
+ S S A/V
42
+ Wb S V.s
43
+ weber P Wb
44
+ farad P coulomb/volt
45
+ T S Wb.m-2
46
+ tesla P Wb.m-2
47
+ H S Wb.A-1
48
+ degC S K @ 273.15
49
+ deg_C S K @ 273.15
50
+ degree_C S K @ 273.15
51
+ degree_c S K @ 273.15
52
+ degreeC S K @ 273.15
53
+ Celsius P K @ 273.15
54
+ celsius P K @ 273.15
55
+ centigrade P K @ 273.15
56
+ degree_R S K / 1.8
57
+ degree_f S degree_R @ 459.67
58
+ degree_F S degree_R @ 459.67
59
+ Fahrenheit P degree_F
60
+ fahrenheit P degree_F
61
+ degF S degree_F
62
+ deg_F S degree_F
63
+ degreeF S degree_F
64
+ lm S cd.sr
65
+ lx S lm.m-2
66
+ Bq S s-1
67
+ Gy S J.kg-1
68
+ Sv S J.kg-1
69
+ #
70
+ # === non-SI units ===
71
+ #
72
+ # --- basic numbers ---
73
+ #
74
+ pi N 3.141592653589793238462
75
+ #
76
+ # --- nondimensional units ---
77
+ #
78
+ percent S 1e-2
79
+ % S 1e-2
80
+ permil S 1e-3
81
+ #
82
+ # --- length ---
83
+ #
84
+ fermi P 1.0e-15 m
85
+ angstrom P 1.0e-10 m
86
+ micron P 1.0e-6 m
87
+ astronomical_unit N 1.49597870e11 m
88
+ astronomical_units N 1.49597870e11 m
89
+ Au S astronomical_unit
90
+ parsec P 3.0857e16 m
91
+ pc S parsec
92
+ light_year N 9.46e15 m
93
+ light_years N 9.46e15 m
94
+ ly S light_year
95
+ nautical_mile N 1852 m
96
+ nautical_miles N 1852 m
97
+ #
98
+ inch P 2.54 cm
99
+ in S inch
100
+ foot N 12 inch
101
+ feet N foot
102
+ ft N foot
103
+ yard P 6 feet
104
+ yd P yard
105
+ chain P 22 yard
106
+ mile P 1760 yard
107
+ #
108
+ # --- time ---
109
+ #
110
+ minute P 60 s
111
+ min S 60 s
112
+ hour P 60 min
113
+ hr S 60 min
114
+ h S 60 min
115
+ day P 24 hour
116
+ d S 24 hour
117
+ Julian_year P 365.25 day
118
+ common_year P 365 day
119
+ #
120
+ # --- date ---
121
+ #
122
+ # date is NOT time intentionally
123
+ #
124
+ pentad P
125
+ month P 6 pentad
126
+ mon S month
127
+ year P 12 month
128
+ yr S year
129
+ century P 100 year
130
+ #
131
+ # --- area ---
132
+ #
133
+ are P 100 m2
134
+ a S are
135
+ hectare P 100 are
136
+ litre P 1.0e-3 m3
137
+ L S litre
138
+ acre P 10 chain2
139
+ ac S acre
140
+ #
141
+ # --- angle ---
142
+ #
143
+ degree P pi.rad/180
144
+ angular_degree P degree
145
+ minute_angle P pi.rad/180/60
146
+ angular_minute P minute_angle
147
+ second_angle P pi.rad/180/60/60
148
+ angular_second P second_angle
149
+ degree_N S degree
150
+ degree_E S degree
151
+ degree_W S degree
152
+ degree_S S degree
153
+ degree_north S degree_N
154
+ degree_east S degree_E
155
+ degree_west S degree_W
156
+ degree_south S degree_S
157
+ degrees_north S degree_N
158
+ degrees_east S degree_E
159
+ degrees_west S degree_W
160
+ degrees_south S degree_S
161
+ #
162
+ # --- mass ---
163
+ #
164
+ ton P 1000 kg
165
+ tonne P ton
166
+ t S ton
167
+ gram P kg/1000
168
+ g S kg/1000
169
+ pound P 453.6 g
170
+ lb S pound
171
+ ounce P pound / 16
172
+ oz S ounce
173
+ #
174
+ # --- CGS ---
175
+ #
176
+ dyne P g.cm.s-2
177
+ dyn S g.cm.s-2
178
+ bar S 1e6 dyn.cm-2
179
+ mb S bar / 1000
180
+ millibar P bar / 1000
181
+ gal P cm s-2
182
+ Gal S cm s-2
183
+ mgal S cm s-2 / 1000
184
+ erg S dyn cm
185
+ erg P dyn cm
186
+ poise P dyn s / cm2
187
+ P S poise
188
+ stokes P cm2 / s
189
+ St S stokes
190
+ gauss P T / 10000
191
+ G S gauss
192
+ #
193
+ # --- conventional ---
194
+ #
195
+ calorie P 4.18605 J
196
+ cal S calorie
197
+ kgf S kilogram-force
198
+ force S 9.80665 m.s-2
199
+ knot P nautical_mile / hour
200
+ horse_power N 75 m kilogram-force / s
201
+ atmosphere P 101325 Pa
202
+ atm S atmosphere
203
+ light_speed N 299792458 m/s
204
+ mph S mile / hour
205
+ kph S km / hour
206
+ torr P 133.322 Pa
207
+ psi S pound-force / inch2
208
+ gravity S 9.806650 meter/second2
209
+ conventional_mercury S gravity 13595.10 kg/m3
210
+ mercury S conventional_mercury
211
+ Hg S mercury
212
+ hg S mercury
data/src/lex.rb ADDED
@@ -0,0 +1,434 @@
1
+ def initialize string
2
+ case string
3
+ when String
4
+ @string, @ptree = string, nil
5
+ when Node
6
+ @string, @ptree = nil, string
7
+ else
8
+ @string, @ptree = String(string), nil
9
+ end
10
+ @copy = @lexstat = nil
11
+ end
12
+
13
+ #
14
+ # === LEXICAL ANALYZER ===
15
+ #
16
+
17
+ def rewind
18
+ @copy = @string.dup.strip
19
+ @lexstat = nil
20
+ end
21
+
22
+ RE_SPACE = '([ \t])'
23
+ RE_INTEGER = '([-+]?\d+)'
24
+ RE_EXP = '([eE][-+]?[0-9]+)'
25
+ RE_REAL = "([-+]?[0-9]*(\\.[0-9]*#{RE_EXP}?|#{RE_EXP}))"
26
+ RE_YEAR = "([-+]?[0-9]{1,4})"
27
+ RE_MONTH = "(0?[1-9]|1[0-2])"
28
+ RE_DAY = "([12][0-9]|30|31|0?[1-9])"
29
+ RE_HOUR = "(2[0-3]|[0-1]?[0-9])"
30
+ RE_MINUTE = "([0-5]?[0-9])"
31
+ RE_SECOND = "((#{RE_MINUTE}|60)(\\.[0-9]*)?)"
32
+ RE_NAME = "(%|[a-zA-Z][a-zA-Z_]*([0-9]+[a-zA-Z_]+)*)"
33
+
34
+ RE_DATE = "#{RE_YEAR}-#{RE_MONTH}-#{RE_DAY}"
35
+ RE_TIME = "#{RE_HOUR}((:[0-5]?[0-9]|[0-5][0-9])(:#{RE_SECOND})?)?"
36
+ RE_HandM = "#{RE_HOUR}((:[0-5]?[0-9]|[0-5][0-9]))?"
37
+
38
+ def next_token
39
+
40
+ # decomment
41
+ @copy.sub!(/^#.*/, '');
42
+
43
+ if @copy.sub!(%r{^\s*(\))}, '') then
44
+ @lexstat = nil
45
+ return [$1, $1]
46
+ end
47
+
48
+ if @copy.sub!(%r{^\s*(\()\s*}, '') then
49
+ return [$1, $1]
50
+ end
51
+
52
+ if @copy.sub!(%r{^[ \t]*(@)[ \t]*}, '') \
53
+ or @copy.sub!(%r{^[ \t]+(after|from|since|ref)[ \t]+}i, '') then
54
+ @lexstat = :SHIFT_SEEN
55
+ return [:SHIFT, $1]
56
+ end
57
+
58
+ if @copy.sub!(%r{^[ \t]*(/)[ \t]*}, '') \
59
+ or @copy.sub!(%r{^[ \t]+(per)[ \t]+}i, '') then
60
+ @lexstat = nil
61
+ return [:DIVIDE, $1]
62
+ end
63
+
64
+ if @copy.sub!(%r{^(\^|\*\*)}, '') then
65
+ @lexstat = nil
66
+ return [:EXPONENT, $1]
67
+ end
68
+
69
+ if @copy.sub!(%r{^(\.|\*|[ \t]+)}, '') then
70
+ @lexstat = nil
71
+ return [:MULTIPLY, $1]
72
+ end
73
+
74
+ if :SHIFT_SEEN === @lexstat \
75
+ and @copy.sub!(%r{^#{RE_DATE}T?[ \t]*}, '') then
76
+ y, m, d = $1, $2, $3
77
+ @lexstat = :DATE_SEEN
78
+ return [:DATE, XDate.new(y.to_i, m.to_i, d.to_i)]
79
+ end
80
+
81
+ if :SHIFT_SEEN === @lexstat \
82
+ and @copy.sub!(%r{^now[ \t]*}, '') then
83
+ @lexstat = nil
84
+ return [:DATE, :now]
85
+ end
86
+
87
+ if :DATE_SEEN === @lexstat \
88
+ and @copy.sub!(%r{^#{RE_TIME}[ \t]*}, '') then
89
+ h, m, s = $1, $3, $5
90
+ m = m.sub(/:/,'') if m
91
+ s = 0 if s.nil?
92
+ @lexstat = :TIME_SEEN
93
+ return [:TIME, ((h.to_i * 60 + m.to_i) * 60 + Float(s))]
94
+ end
95
+
96
+ if :DATE_SEEN === @lexstat \
97
+ and @copy.sub!(%r{^([0-2][0-9])([0-5][0-9])[ \t]*}, '') then
98
+ h, m = $1, $2
99
+ @lexstat = :TIME_SEEN
100
+ return [:TIME, ((h.to_i * 60 + m.to_i) * 60.0)]
101
+ end
102
+
103
+ if :DATE_SEEN === @lexstat \
104
+ and @copy.sub!(%r{^([0-9])([0-5][0-9])[ \t]*}, '') then
105
+ h, m = $1, $2
106
+ @lexstat = :TIME_SEEN
107
+ return [:TIME, ((h.to_i * 60 + m.to_i) * 60.0)]
108
+ end
109
+
110
+ if :TIME_SEEN === @lexstat \
111
+ and @copy.sub!(%r{^UTC[ \t]*}, '') then
112
+ @lexstat = nil
113
+ return [:ZONE, 0]
114
+ end
115
+
116
+ if :TIME_SEEN === @lexstat \
117
+ and @copy.sub!(%r{^([-+]?)#{RE_HandM}[ \t]*}, '') then
118
+ sgn, h, m = $1, $2, $4
119
+ m = m.sub(/:/,'') if m
120
+ @lexstat = nil
121
+ h = h.to_i
122
+ h = -h if sgn == "-"
123
+ m = m.to_i
124
+ m = -m if sgn == "-"
125
+ return [:ZONE, ((h * 60) + m)]
126
+ end
127
+
128
+ if @copy.sub!(%r{^#{RE_NAME}}, '') then
129
+ @lexstat = nil
130
+ return [:NAME, $1]
131
+ end
132
+
133
+ if @copy.sub!(%r{^#{RE_REAL}}, '') then
134
+ @lexstat = nil
135
+ return [:REAL, $1.to_f]
136
+ end
137
+
138
+ if @copy.sub!(%r{^#{RE_INTEGER}}, '') then
139
+ @lexstat = nil
140
+ return [:INT, $1.to_i]
141
+ end
142
+
143
+ if @copy.sub!(%r{^(-)}, '') then
144
+ @lexstat = nil
145
+ return [:MULTIPLY, $1]
146
+ end
147
+
148
+ if @copy.sub!(%r{^(.)}, '') then
149
+ return [$1, $1]
150
+ end
151
+
152
+ return [false, false]
153
+
154
+ end
155
+
156
+ #
157
+ # === USER LEVEL METHODS ===
158
+ #
159
+
160
+ def tokens
161
+ rewind
162
+ x = []
163
+ while (t = next_token).first
164
+ x.push t
165
+ end
166
+ x
167
+ end
168
+
169
+ def do_parse2
170
+ rewind
171
+ return NumberNode.new(1) if @string.nil? or @string.empty?
172
+ pa = do_parse
173
+ pa ? pa : ErrorNode.new(@string)
174
+ end
175
+
176
+ def ptree
177
+ @ptree = do_parse2 if not @ptree
178
+ @ptree
179
+ end
180
+
181
+ def dup
182
+ @string ? self.class.new(@string) : self.class.new(@ptree)
183
+ end
184
+
185
+ def parse
186
+ dup.parse!
187
+ end
188
+
189
+ def parse!
190
+ @ptree = do_parse2 if not @ptree
191
+ self
192
+ end
193
+
194
+ def self::parse(string)
195
+ new(string).parse!
196
+ end
197
+
198
+ =begin
199
+ --- reduce0
200
+ just do nothing.
201
+ =end
202
+
203
+ def reduce0
204
+ self
205
+ end
206
+
207
+ =begin
208
+ --- reduce1
209
+ removes unnecessary parentheses.
210
+ =end
211
+
212
+ def reduce1
213
+ @string = ptree.to_s
214
+ self
215
+ end
216
+
217
+ =begin
218
+ --- reduce2
219
+ removes shift operator within multiplication/division/exponent
220
+ =end
221
+
222
+ def reduce2
223
+ @ptree = ptree.reduce2
224
+ @string = nil
225
+ self
226
+ end
227
+
228
+ =begin
229
+ --- reduce3
230
+ flattens expression and collects all factors
231
+ =end
232
+
233
+ def reduce3
234
+ @ptree = ptree.reduce3
235
+ @string = nil
236
+ self
237
+ end
238
+
239
+ =begin
240
+ --- reduce4
241
+ collects terms with the same name
242
+ =end
243
+
244
+ def reduce4
245
+ @ptree = ptree.reduce4
246
+ @string = nil
247
+ self
248
+ end
249
+
250
+ =begin
251
+ --- reduce5
252
+ expands all terms recursively
253
+ =end
254
+
255
+ def reduce5
256
+ @ptree = ptree.reduce5
257
+ @string = nil
258
+ self
259
+ end
260
+
261
+ attr_reader :string
262
+
263
+ def to_s
264
+ @string = @ptree.to_s if @string.nil?
265
+ @string
266
+ end
267
+
268
+ def inspect
269
+ if @ptree.nil? then
270
+ "Units{#{@string}}"
271
+ else
272
+ "Units[#{@ptree.inspect}]".gsub(/Units::/, '').gsub(/Node\[/, '[')
273
+ end
274
+ end
275
+
276
+ def self::[](string)
277
+ new(string)
278
+ end
279
+
280
+ def self::parse(string)
281
+ new(string).parse!
282
+ end
283
+
284
+ def eval(x = 0)
285
+ r5 = ptree.reduce5
286
+ case r = r5.ref
287
+ when TimeNode
288
+ r.add(x, r5.name)
289
+ else
290
+ fac = NumberNode.new(x + r.value)
291
+ self.class.new(MulNode.new(fac, r5.deref))
292
+ end
293
+ end
294
+
295
+ def convert(numeric, to_units)
296
+ to_units = Units.new( to_units ) if to_units.is_a?(String)
297
+ r5 = dup.ptree.reduce5
298
+ case r = r5.ref
299
+ when TimeNode
300
+ r.add_time(r5.deref.mul(numeric)).div_time(to_units.ptree)
301
+ else
302
+ shift1 = r.value
303
+ numeric = shift1 + numeric if shift1 != 0
304
+ fact = r5.divide(tp = to_units.dup.ptree).reduce5.value
305
+ numeric *= fact if fact != 1
306
+ shift2 = tp.reduce5.ref.value
307
+ numeric = numeric - shift2 if shift2 != 0
308
+ numeric
309
+ end
310
+ end
311
+
312
+ def factor_and_offset(to_units)
313
+ # To convert a numeric from self to to_units:
314
+ # scale_factor * numeric + add_offset
315
+ to_units = Units.new( to_units ) if to_units.is_a?(String)
316
+ add_offset = convert(0, to_units)
317
+ scale_factor = convert(1, to_units) - add_offset
318
+ [ scale_factor, add_offset ]
319
+ end
320
+
321
+ def convert2(val, to_units)
322
+ # Like Units#convert, but applicable to any Numeric-like objects.
323
+ # Returns the original value if the units are incompatible.
324
+ to_units = Units.new( to_units ) if to_units.is_a?(String)
325
+ if ( self == to_units )
326
+ val
327
+ elsif ( self =~ to_units )
328
+ if Numeric===val
329
+ convert( val, to_units )
330
+ else
331
+ factor, offset = factor_and_offset( to_units )
332
+ val*factor + offset
333
+ end
334
+ else
335
+ unless $VERBOSE.nil?
336
+ $stderr.print( "*WARNING*: " +
337
+ "incompatible units: #{self.to_s} and #{to_units.to_s}\n")
338
+ caller(0).each{|c| $stderr.print "\t* ",c,"\n"}
339
+ end
340
+ val
341
+ end
342
+ end
343
+
344
+ @@reduce = :reduce4
345
+
346
+ def self::reduce_level
347
+ @@reduce.to_s[-1]
348
+ end
349
+
350
+ def self::reduce_level=(n)
351
+ @@reduce = case n
352
+ when 1 then :reduce1
353
+ when 2 then :reduce2
354
+ when 3 then :reduce3
355
+ when 4 then :reduce4
356
+ else :reduce5
357
+ end
358
+ end
359
+
360
+ def binop(op, other)
361
+ case other
362
+ when Numeric
363
+ other = NumberNode.new(other)
364
+ when Units
365
+ other = other.ptree
366
+ end
367
+ q = self.ptree.send(op, other).send(@@reduce)
368
+ Units.new(q)
369
+ end
370
+
371
+ def *(other)
372
+ binop(:mul, other)
373
+ end
374
+
375
+ def **(other)
376
+ binop(:pow, other)
377
+ end
378
+
379
+ def /(other)
380
+ binop(:divide, other)
381
+ end
382
+
383
+ def ^(other)
384
+ binop(:shift, other)
385
+ end
386
+
387
+ def ==(other)
388
+ case other
389
+ when self.class
390
+ dup.reduce5.to_s == other.dup.reduce5.to_s
391
+ else
392
+ false
393
+ end
394
+ end
395
+
396
+ #def === (other)
397
+ # reduce5.ptree.deref.to_s == other.reduce5.ptree.deref.to_s
398
+ #end
399
+
400
+ alias === ==
401
+
402
+ #def === (other)
403
+ # # returns true if other is within a factor and/or offset of difference.
404
+ # case other
405
+ # when self.class
406
+ # (self/other).reduce5.ptree.children.each do |child|
407
+ # return false if !( NumberNode === child )
408
+ # end
409
+ # true
410
+ # else
411
+ # false
412
+ # end
413
+ #end
414
+
415
+
416
+ def =~(other)
417
+ case other
418
+ when self.class
419
+ (self/other).reduce5.ptree.children.each{ |node|
420
+ return false unless NumberNode === node
421
+ }
422
+ true
423
+ else
424
+ false
425
+ end
426
+ end
427
+
428
+ def self::pow_f(a, b)
429
+ if Integer === b and b < 0 then
430
+ a ** b.to_f
431
+ else
432
+ a ** b
433
+ end
434
+ end